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!