net.sf.json.JSONException: There is a cycle in the hierarchy!

Posted zhumengke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了net.sf.json.JSONException: There is a cycle in the hierarchy!相关的知识,希望对你有一定的参考价值。

转自:https://blog.csdn.net/waysoflife/article/details/24351051

原因分析:

这个异常是由于JSONObject插件内部会无限拆解你传入的对象,直到没有可拆解为止,在解析bean时,出现死循环调用,即:多个Bean之间出现了相互调用。问题就在这,如果你传入的对象有外键关系,或者相互引用,那么内部就会死循环,也就会抛出这个异常解决办法,我们先说一种网上通用的:过滤不错,过滤肯定会解决该问题,过滤也有两种方法:

解决办法一:过滤去掉bean中引起死循环调用的属性:

List<Project> projectList = projectServices.find();  //获取数据
//自定义JsonConfig用于过滤Hibernate配置文件所产生的递归数据
JsonConfig config = new JsonConfig();
config.setExcludes(new String[]{"documentSet","milestoneSet","issuesSet","userSet"});  //只要设置这个数组,指定过滤哪些字段。   
//组成JSON数组
JSONArray json = JSONArray.fromObject(projectList, config);

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

 解决办法 二

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是你要处理的属性类型

  

 

以上是关于net.sf.json.JSONException: There is a cycle in the hierarchy!的主要内容,如果未能解决你的问题,请参考以下文章

net.sf.json.JSONException: There is a cycle in the hierarchy!

ajax请求json数据异常:nested exception is net.sf.json.JSONException: java.lang.reflect.InvocationTargetExce

json数据转换异常:net.sf.json.JSONException: java.lang.reflect.InvocationTargetException

json格式错误:net.sf.json.JSONException: A JSONObject text must begin with '' at character 1 of 2

net.sf.json.JSONException: There is a cycle in the hierarchy!

net.sf.json.JSONException: There is a cycle in the hierarchy!错误解决方案