1. 程式人生 > >net.sf.json.JSONException: There is a cycle in the hierarchy!

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

遞歸 組裝 set mil 對象 數組 tail csdn 都沒有

轉自: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!