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

因为项目中使用了AJAX技术,jar包为:json-lib.jar,在开发过程中遇到了一个JSON-LIB和Hibernate有关的问题:

如hibernate延迟加载错误,这都是些老问题了,一看就知道加个lazy=flase就OK了。想不到快要完成了又遇到了新的问题,JSON死循环,实在让人郁闷。异常如下:

net.sf.json.JSONException: There is a cycle in the hierarchy!
at net.sf.json.util.CycleDetectionStrategy$StrictCycleDetectionStrategy.handleRepeatedReferenceAsObject(CycleDetectionStrategy.java:97)
at net.sf.json.JSONObject._fromBean(JSONObject.java:857)
at net.sf.json.JSONObject.fromObject(JSONObject.java:192)
at net.sf.json.JSONObject._processValue(JSONObject.java:2774)
at net.sf.json.JSONObject._setInternal(JSONObject.java:2798)
at net.sf.json.JSONObject.setValue(JSONObject.java:1507)
at net.sf.json.JSONObject._fromBean(JSONObject.java:940)
at net.sf.json.JSONObject.fromObject(JSONObject.java:192)
at net.sf.json.JSONObject._processValue(JSONObject.java:2774)
at net.sf.json.JSONObject._setInternal(JSONObject.java:2798)
at net.sf.json.JSONObject.setValue(JSONObject.java:1507)
at net.sf.json.JSONObject._fromBean(JSONObject.java:940)
at net.sf.json.JSONObject.fromObject(JSONObject.java:192)
at net.sf.json.JSONObject._processValue(JSONObject.java:2774)
at net.sf.json.JSONObject._setInternal(JSONObject.java:2798)
at net.sf.json.JSONObject.setValue(JSONObject.java:1507)
at net.sf.json.JSONObject._fromBean(JSONObject.java:940)
at net.sf.json.JSONObject.fromObject(JSONObject.java:192)
at net.sf.json.JSONObject._processValue(JSONObject.java:2774)
at net.sf.json.JSONObject._setInternal(JSONObject.java:2798)
at net.sf.json.JSONObject.setValue(JSONObject.java:1507)
at net.sf.json.JSONObject._fromBean(JSONObject.java:940)
at net.sf.json.JSONObject.fromObject(JSONObject.java:192)
at net.yanhl.iouser.action.IOUserAction.loadUser(IOUserAction.java:142)

因为Hibernate中设置了自身关联: Iouser.hbm.xml:

<many-to-one name="group" class="net.yanhl.iouser.pojo.GroupRelation" lazy="false" cascade="none">
<column name="group_id"></column>
</many-to-one>

//设置自身关联的组对象

 1 public class GroupRelation implements Serializable {
 2 
 3    private static final long serialVersionUID = 6202253180943473205L;
 4 
 5    private Integer id;// 主键ID
 6 
 7    private Integer creatorId;// 创建人
 8 
 9    private Date createDate;// 创建日期
10 
11    private String groupName;// 组名称
12 
13    private GroupRelation parentGroup;
14  
15    private Set<grouprelation> childGroups = new HashSet<grouprelation>();
16    /******** get set  ********/
17  }
<many-to-one name="parentGroup" column="parent_id" lazy="false" class="net.yanhl.iouser.pojo.GroupRelation">
</many-to-one> 
<set name="childGroups" cascade="save-update" inverse="true">
<key column="parent_id"></key>
<one-to-many class="net.yanhl.iouser.pojo.GroupRelation"></one-to-many>
</set>

起初想通过hibernate来解决问题,就是想过滤掉自身关联后来查资料发现不可能实现,最后找到通过JSON-LIB来过滤关联的集合属性。

仔细查了一下发现是hibernate主外键关联的错,后来就想下json源代码下来看,发现大费周章都没搞到json源码,还是老办法反编译瞅瞅,发现JSONArray根据判断取得的不同类型调用相应的方法,

if (object instanceof Collection)
    return _fromCollection((Collection)object, jsonConfig);

而我从hibernate那得到的是list,所以去调用了_fromCollection方法,而里面的方法发现一个问题:该方法会不断的拆开实体属性,直到没有为止,而我的GroupRelation里有两个属性用于自身关联

private GroupRelation parentGroup;

 

private Set<grouprelation> childGroups = new HashSet<grouprelation>();

也就是说主外键自身关联的是个死循环,那怎么才能不让他出现这种情况呢,应该有个配置的参数后者终止循环的地方吧,查看发
现,jsonConfig,呵呵,config应该是配置参数吧,参看JsonConfig看见巨多的属性,有点晕PropertyFilter 
,不提了,看了老半天,发现了一个属性PropertyFilter,PropertyFilter 是一个interface,代码如下:

public interface PropertyFilter{

  public abstract boolean apply(Object obj, String s, Object obj1);
}

也就是说我可以通过这个方法过滤掉List里的相应属性,只要让它返回true就可过滤掉,我们重写一下这个方法,代码如下:

 1 JsonConfig config = new JsonConfig();
 2 
 3 config.setJsonPropertyFilter(new PropertyFilter(){
 4 
 5     public boolean apply(Object source, String name, Object value) {
 6 
 7         if(name.equals("parentGroup") || name.equals("childGroups")) {
 8 
 9             return true;
10 
11         } else {
12 
13             return false;
14 
15         }
16 
17     }
18 
19 });
20 
21 Iouser user = (Iouser) getBaseManager().get(Iouser.class, iouserId);
22 
23 JSONObject jsonObject = JSONObject.fromObject(user, config);

将hibernate产生的实体bean中的parentGroup和childGroups过滤掉就OK了!

然后调用JSONArray.fromObject(user,config); user是hibernate返回的list。

当JSON-LIB解析JAVABEAN时过滤掉parentGroup、childGroups这两个属性,重新启动服务,pass

搞了一早上,参考网络的资料!解决问题了!

原文地址:https://www.cnblogs.com/xinzehome/p/3722843.html