There is a cycle in the hierarchy解决办法

本文介绍了一种使用自定义JsonValueProcessor解决JSON从Object抛出There is a cycle in the hierarchy异常的方法,避免了在处理有外键关系或相互引用的对象时出现的死循环问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信大家做过JSON相关的东西对这个异常并不陌生,这个异常是由于JSONObject插件内部会无限拆解你传入的对象,直到没有可拆解为止,问题就在这,如果你传入的对象有外键关系,或者相互引用,那么内部就会死循环,也就会抛出这个异常
解决办法,我们先说一种网上通用的:过滤
     不错,过滤肯定会解决该问题,过滤也有两种方法:

     一种是通过

jsonConfig.setExcludes(new String[]{"dianYuanHeSuans"})
 

    该方法接受一个数组,也就是你需要过滤的字段,很简单就能完成。
     二种是通过

jsonConfig.setJsonPropertyFilter(new PropertyFilter() {
			
			@Override
			public boolean apply(Object source, String name, Object value) {
				if(name.equals("qualityChecks")){
					return true;
				}
				return false;
			}
		});
 

这种方式,其实和第一种差不多,达到同样的效果,也很简单。

接下来是我主要想说的,其实这两种方法,有种弊端

假如说我们一个User对象里有个属性是部门,引用的是Organzition这个对象,如果不做任何处理,调用JSONObject.fromObject方法同样会抛出异常,如果我们通过过滤把Organzition属性过滤了,那么在前台显示的时候,将看不到有关部门的任何信息,其实需要显示也不多,比如仅一个部门名字就可以,但是过滤掉什么都没有了,这个时候,很多同学会再建一个VO类来封装前台需要的属性,这无疑增加了工作量和代码的冗余,LZ正是被该问困扰了很久,所以给出个解决办法。

 

借用JSONObject里的JsonValueProcessor接口,我们自己实现该接口,代码如下:

/**
 * 解决JSONObject.fromObject抛出"There is a cycle in the hierarchy"异常导致死循环的解决办法
 * @author LuoYu
 * @date 2012-11-23
 */
public class ObjectJsonValueProcessor implements JsonValueProcessor {
	
	/**
	 * 需要留下的字段数组
	 */
	private String[] properties;
	
	/**
	 * 需要做处理的复杂属性类型
	 */
	private Class<?> clazz;
	
	/**
	 * 构造方法,参数必须
	 * @param properties
	 * @param clazz
	 */
	public ObjectJsonValueProcessor(String[] properties,Class<?> clazz){
		this.properties = properties;
		this.clazz =clazz;
	}

	@Override
	public Object processArrayValue(Object value, JsonConfig jsonConfig) {
		return "";
	}

	@Override
	public Object processObjectValue(String key, Object value, JsonConfig jsonConfig) {
		PropertyDescriptor pd = null;
		Method method = null;
		StringBuffer json = new StringBuffer("{");
		try{
			for(int i=0;i<properties.length;i++){
				pd = new PropertyDescriptor(properties[i], clazz);
				method = pd.getReadMethod();
				String v = String.valueOf(method.invoke(value));
				json.append("'"+properties[i]+"':'"+v+"'");
				json.append(i != properties.length-1?",":"");
			}
			json.append("}");
		}catch (Exception e) {
			e.printStackTrace();
		}
		return JSONObject.fromObject(json.toString());
	}
	
	
}

      在processObjectValue这个方法里重写,具体请看代码,另外在构造方法里我给出了两个参数,一个是需要留下来的属性名,通过数组传递,另一个是一个Class<?> type,也是相关上面说到例子中的Organzition.class,是用来在后面通过该class调用java反射机制获取属性值,在取到相关属值后组装成字符串,最后通过JSONObject.fromObject来输出,不这样输出会有问题,至于什么问题,有好奇心的同学自己试试

下面是调用方法:

jsonConfig.registerJsonValueProcessor(Organzition.class, 
       new ObjectJsonValueProcessor(new String[]{"orgName","orgId"},Organzition.class));
 

其中,Organzition.class是你要处理的属性类型

 

### JSONException 的原因及解决方案 #### 错误原因分析 `JSONException` 是 JSON 解析过程中常见的异常,通常表示解析的字符串不符合标准的 JSON 格式。以下是几个常见场景及其可能的原因: 1. **循环引用问题** 当对象层次结构中存在循环依赖时,JSON 序列化工具无法正常处理这种关系,从而抛出 `net.sf.json.JSONException: There is a cycle in the hierarchy!` 异常[^1]。 2. **语法错误** 如果输入的字符串不是合法的 JSON 数据,则会触发类似于 `com.alibaba.fastjson.JSONException: syntax error, pos 1, line 1, column` 这样的异常[^2]。这可能是由于缺少括号、引号不匹配或其他格式问题引起的。 3. **未闭合字符串** 另一种情况是当 JSON 字符串中的某些部分未能正确结束(例如双引号缺失),则会出现 `com.alibaba.fastjson.JSONException: unclosed string` 提示[^3]。 #### 解决方案详解 针对上述提到的各种类型的 `JSONException`,可以采取如下措施来解决问题: 1. **对于循环引用的情况** 需要修改数据模型或者调整序列化的配置选项以打破循环链路。比如,在使用 FastJSON 时可以通过设置参数忽略特定字段或禁用循环检测功能: ```java JSONObject.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect); ``` 2. **修复非法字符引发的语法错误** 确认传入的数据确实遵循 RFC 4627 定义的标准形式;必要时候借助正则表达式清理脏数据后再传递给解析器尝试重新加载。 3. **补全遗漏的终止标记** 检查原始文本是否存在任何悬而未决的状态(如开放的大括号 `{` 或者方括号 `[` 而无对应的关闭符号)。一旦发现此类状况即刻修正相应位置的内容直至满足完整的语法规则为止。 通过以上方法能够有效应对大部分由 `JSONException` 所带来的挑战并保障程序稳定运行。 ```python import json try: data = '{"key": "value"' parsed_data = json.loads(data) # This will raise an exception due to missing closing brace. except ValueError as e: print(f"Parsing failed: {e}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值