我們在撰寫相關網頁時,有可能利用到JSONObject或JSONArray來包裝相關的response value
值給前端JavaScript做parse,進而得到相關訊息!當碰到net.sf.json.JSONException: There is a
cycle in the hierarchy!時,有可能是使用JSON上哪裡出了問題?
測試JSON Library版本為json-lib-2.0-jdk15.jar
在這邊撰寫一段簡單的TEST程式
定義一Employees.java及TestJSON.java
定義一Employees類別,當new一object時並做相關的set values,此時可透過JSONObject的
fromObject來將Employees轉換成一key, value的JSONObject,key為相關的成員變數,而values
為相關set的值。但以此例會出現net.sf.json.JSONException: There is a cycle in the hierarchy!
的錯誤訊息!
追蹤了一下其source code,發現在JSONObject會去檢查相關特別型態的values值是否存在於
cycleSet內了,若已存在則跳出該Exception!! 以此例會走_fromBean( object );
=> addInstance由AbstractJSON父類別宣告
也就是說它會去作類別是否相等,以Employees來說若宣告了兩個objects,其equals的依據
employeeid皆相同,此時利用cycleSet加入第一次為true(bean本身),若加入第二次則為false!
第二次指的是當處理bean下的成員變數要設為JSONObject的key map value時,當做到self的
setValue時會執行到
1005行 ==> jsonObject._setInternal( key, value );
2177行 ==> this.properties.put( key, _processValue( value ) );
在過來又回到fromObject,此時method又去判斷該value為int or JSONString or ....
再次執行_fromBean( object ); 此時再add當時set到self成員內的bean2,cycleSet發現Employee
類別下的object已存在了,因此會return false!因此程式便會進入
return jsonConfig.getCycleDetectionStrategy()
.handleRepeatedReferenceAsObject( bean );
JsonConfig.java預設會走Strict mode,因此jsonConfig.getCycleDetectionStrategy()物件所呼
叫的為StrictCycleDetectionStrategy的method而非LenientCycleDetectionStrategy
CycleDetectionStrategy.java如下:
若要防止Exception發生,可設定走
此時將會印出
{"employeeid":123,"department":"","employeename":"","self":null,"salary":0}
原本self的值應該為{"employeeid:....,此時會為null
或改code為bean2.setEmployeeid(456);
此時印出為
{"employeeid":123,"department":"","employeename":"","self":{"employeeid":456,"department":"","employeename":"","self":null,"salary":0},"salary":0}
值給前端JavaScript做parse,進而得到相關訊息!當碰到net.sf.json.JSONException: There is a
cycle in the hierarchy!時,有可能是使用JSON上哪裡出了問題?
在這邊撰寫一段簡單的TEST程式
定義一Employees.java及TestJSON.java
public class Employees extends PrimaryBean{
private int employeeid;
private String employeename;
private String department;
private BigDecimal salary;
private Employees self;
//相關setter or getter...略
public boolean equals(Object obj) {
if (obj instanceof Employees) {
Employees compare = (Employees) obj;
return employeeid == compare.getEmployeeid();
} else {
return false;
}
}
public int hashCode() {
return employeeid;
}
}
public class TestJSON {
public static void main(String[] args) {
// TODO Auto-generated method stub
Employees bean = new Employees();
Employees bean2 = new Employees();
bean.setEmployeeid(123);
bean2.setEmployeeid(123);
bean.setSelf(bean2);
JSONObject object = JSONObject.fromObject(bean);
System.out.println(object);
}
}
定義一Employees類別,當new一object時並做相關的set values,此時可透過JSONObject的
fromObject來將Employees轉換成一key, value的JSONObject,key為相關的成員變數,而values
為相關set的值。但以此例會出現net.sf.json.JSONException: There is a cycle in the hierarchy!
的錯誤訊息!
追蹤了一下其source code,發現在JSONObject會去檢查相關特別型態的values值是否存在於
cycleSet內了,若已存在則跳出該Exception!! 以此例會走_fromBean( object );
private static JSONObject _fromBean( Object bean ) {
...
if( !addInstance( bean ) ){
try{
return jsonConfig.getCycleDetectionStrategy()
.handleRepeatedReferenceAsObject( bean );
}
......
}
}
=> addInstance由AbstractJSON父類別宣告
protected static boolean addInstance( Object instance ) {
return cycleSet.add( instance );
}
也就是說它會去作類別是否相等,以Employees來說若宣告了兩個objects,其equals的依據
employeeid皆相同,此時利用cycleSet加入第一次為true(bean本身),若加入第二次則為false!
第二次指的是當處理bean下的成員變數要設為JSONObject的key map value時,當做到self的
setValue時會執行到
1005行 ==> jsonObject._setInternal( key, value );
2177行 ==> this.properties.put( key, _processValue( value ) );
在過來又回到fromObject,此時method又去判斷該value為int or JSONString or ....
再次執行_fromBean( object ); 此時再add當時set到self成員內的bean2,cycleSet發現Employee
類別下的object已存在了,因此會return false!因此程式便會進入
return jsonConfig.getCycleDetectionStrategy()
.handleRepeatedReferenceAsObject( bean );
JsonConfig.java預設會走Strict mode,因此jsonConfig.getCycleDetectionStrategy()物件所呼
叫的為StrictCycleDetectionStrategy的method而非LenientCycleDetectionStrategy
public class JsonConfig {
private static final CycleDetectionStrategy DEFAULT_CYCLE_DETECTION_STRATEGY =
CycleDetectionStrategy.STRICT;
private CycleDetectionStrategy cycleDetectionStrategy = DEFAULT_CYCLE_DETECTION_STRATEGY;
public CycleDetectionStrategy getCycleDetectionStrategy() {
return cycleDetectionStrategy;
}
.....
}
CycleDetectionStrategy.java如下:
private static final class LenientCycleDetectionStrategy extends CycleDetectionStrategy {
public JSONArray handleRepeatedReferenceAsArray( Object reference ) {
return new JSONArray();
}
public JSONObject handleRepeatedReferenceAsObject( Object reference ) {
return new JSONObject( true );
}
}
private static final class StrictCycleDetectionStrategy extends CycleDetectionStrategy {
public JSONArray handleRepeatedReferenceAsArray( Object reference ) {
throw new JSONException( "There is a cycle in the hierarchy!" );
}
public JSONObject handleRepeatedReferenceAsObject( Object reference ) {
throw new JSONException( "There is a cycle in the hierarchy!" );
}
}
若要防止Exception發生,可設定走
JsonConfig jsonConfig = JsonConfig.getInstance();
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
JSONObject object = JSONObject.fromObject(bean);
此時將會印出
{"employeeid":123,"department":"","employeename":"","self":null,"salary":0}
原本self的值應該為{"employeeid:....,此時會為null
或改code為bean2.setEmployeeid(456);
此時印出為
{"employeeid":123,"department":"","employeename":"","self":{"employeeid":456,"department":"","employeename":"","self":null,"salary":0},"salary":0}
留言
張貼留言