zoukankan      html  css  js  c++  java
  • [转]JSON 转换异常 死循环 There is a cycle in the hierarchy

    转载:http://blog.csdn.net/zhengbo0/article/details/8269148

    问题:

    net.sf.json.JSONException: There is a cycle in the hierarchy!
     at net.sf.json.util.CycleDetectionStrategy$StrictCycleDetectionStrategy.handleRepeatedReferenceAsObject(CycleDetectionStrategy.java:97)

    ***************************************************************************************************************************************************

    在查问一些资料后,总结出解决该问题的两种办法,现在与大家分享一下。

    其一:根据原理来解决,如果需要解析的数据间存在级联关系,而互相嵌套引用,在hibernate中极容易嵌套而抛出net.sf.json.JSONException: There is a cycle in the hierarchy异常。

    举个例子:现在有实验(Lib)和类别(Libtype)两张表,每个实验都对应着一个类别,那么,在类别的POJO中,就会如下代码:

     private Integer ltid; //类别ID
     private String ltype;  //类别名称
     private Set libs = new HashSet(0);  //对应的实验集

    当我们写如下代码时,会报错:

     public ActionForward execute(ActionMapping mapping, ActionForm form,  HttpServletRequest request, HttpServletResponse response){

     LibtypeDAO libtypeDAO = new LibtypeDAO();
     List<Libtype> list = libtypeDAO.findAll();
     JSONArray jsonArray = JSONArray.fromObject(list);

     return null;

    }

    原因很简单,在Libtype中,有一个与List无关的属性值,即libs,我们只需要ltid和ltype,所以报错。

    根据我在网上查找的资料,解决办法有如下3种:

    1.设置JSON-LIB让其过滤掉引起循环的字段:

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){

      LibtypeDAO libtypeDAO = new LibtypeDAO();
      List<Libtype> list = libtypeDAO.findAll();
      JsonConfig jsonConfig = new JsonConfig();  //建立配置文件
      jsonConfig.setIgnoreDefaultExcludes(false);  //设置默认忽略
      jsonConfig.setExcludes(new String[]{"libs"});  //此处是亮点,只要将所需忽略字段加到数组中即可,在上述案例中,所要忽略的是“libs”,那么将其添到数组中即可,在实际测试中,我发现在所返回数组中,存在大量无用属性,如“multipartRequestHandler”,“servletWrapper”,那么也可以将这两个加到忽略数组中.
      JSONArray jsonArray = JSONArray.fromObject(list,jsonConfig);  //加载配置文件
      return null;

    }

    2.设置JSON-LIB的setCycleDetectionStrategy属性让其自己处理循环,省事但是数据过于复杂的话会引起数据溢出或者效率低下。

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){

    LibtypeDAO libtypeDAO = new LibtypeDAO();
    List<Libtype> list = libtypeDAO.findAll();
    JsonConfig jsonConfig = new JsonConfig(); //建立配置文件
    jsonConfig.setIgnoreDefaultExcludes(false); //设置默认忽略
    jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);   //此处是亮点,不过经过测试,第2种方法有些悲剧,虽然可以使用,但其结果貌似循环数次,至于为啥,还请高人指点。
    JSONArray jsonArray = JSONArray.fromObject(list,jsonConfig); //加载配置文件
    return null;

    }

    3.最为原始的办法,自己写个JavaBean,用forEach循环,添加到List中,这个方法我看网上有人成功,我没试,但大概过程可以写出来,其结果正确性有待检验。

    JavaBean:

    public LibtypeForm{

    int ltid;

    string ltname; 

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){

    LibtypeDAO libtypeDAO = new LibtypeDAO();
    List<Libtype> list = libtypeDAO.findAll();

    List<LibtypeForm> formList = new ArrayList();
    for(Libtype libtype : list){

    LibtypeForm form = new LibtypeForm();

    form.setLtid(libtype .getLtid);

    form.setLtname(libtype.getLtname);

    formList.add(form);

    }
    JSONArray jsonArray = JSONArray.fromObject(formList); 
    return null;

    }

    如果有更好的方法,还请高人指点。

    ===========================================================================================

    转载:http://luoyu-ds.iteye.com/blog/1734177

    相信大家做过JSON相关的东西对这个异常并不陌生,这个异常是由于JSONObject插件内部会无限拆解你传入的对象,直到没有可拆解为止,问题就在这,如果你传入的对象有外键关系,或者相互引用,那么内部就会死循环,也就会抛出这个异常
    解决办法,我们先说一种网上通用的:过滤
         不错,过滤肯定会解决该问题,过滤也有两种方法:

         一种是通过

    Java代码  收藏代码
    1. jsonConfig.setExcludes(new String[]{"dianYuanHeSuans"})  

     

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

    Java代码  收藏代码
    1. jsonConfig.setJsonPropertyFilter(new PropertyFilter() {  
    2.               
    3.             @Override  
    4.             public boolean apply(Object source, String name, Object value) {  
    5.                 if(name.equals("qualityChecks")){  
    6.                     return true;  
    7.                 }  
    8.                 return false;  
    9.             }  
    10.         });  

     

    这种方式,其实和第一种差不多,达到同样的效果,也很简单。

    接下来是我主要想说的,其实这两种方法,有种弊端

    假如说我们一个User对象里有个属性是部门,引用的是Organzition这个对象,如果不做任何处理,调用JSONObject.fromObject方法同样会抛出异常,如果我们通过过滤把Organzition属性过滤了,那么在前台显示的时候,将看不到有关部门的任何信息,其实需要显示也不多,比如仅一个部门名字就可以,但是过滤掉什么都没有了,这个时候,很多同学会再建一个VO类来封装前台需要的属性,这无疑增加了工作量和代码的冗余,LZ正是被该问困扰了很久,所以给出个解决办法。

    借用JSONObject里的JsonValueProcessor接口,我们自己实现该接口,代码如下:

    Java代码  收藏代码
    1. /** 
    2.  * 解决JSONObject.fromObject抛出"There is a cycle in the hierarchy"异常导致死循环的解决办法 
    3.  * @author LuoYu 
    4.  * @date 2012-11-23 
    5.  */  
    6. public class ObjectJsonValueProcessor implements JsonValueProcessor {  
    7.       
    8.     /** 
    9.      * 需要留下的字段数组 
    10.      */  
    11.     private String[] properties;  
    12.       
    13.     /** 
    14.      * 需要做处理的复杂属性类型 
    15.      */  
    16.     private Class<?> clazz;  
    17.       
    18.     /** 
    19.      * 构造方法,参数必须 
    20.      * @param properties 
    21.      * @param clazz 
    22.      */  
    23.     public ObjectJsonValueProcessor(String[] properties,Class<?> clazz){  
    24.         this.properties = properties;  
    25.         this.clazz =clazz;  
    26.     }  
    27.   
    28.     @Override  
    29.     public Object processArrayValue(Object value, JsonConfig jsonConfig) {  
    30.         return "";  
    31.     }  
    32.   
    33.     @Override  
    34.     public Object processObjectValue(String key, Object value, JsonConfig jsonConfig) {  
    35.         PropertyDescriptor pd = null;  
    36.         Method method = null;  
    37.         StringBuffer json = new StringBuffer("{");  
    38.         try{  
    39.             for(int i=0;i<properties.length;i++){  
    40.                 pd = new PropertyDescriptor(properties[i], clazz);  
    41.                 method = pd.getReadMethod();  
    42.                 String v = String.valueOf(method.invoke(value));  
    43.                 json.append("'"+properties[i]+"':'"+v+"'");  
    44.                 json.append(i != properties.length-1?",":"");  
    45.             }  
    46.             json.append("}");  
    47.         }catch (Exception e) {  
    48.             e.printStackTrace();  
    49.         }  
    50.         return JSONObject.fromObject(json.toString());  
    51.     }  
    52.       
    53.       
    54. }  

          在processObjectValue这个方法里重写,具体请看代码,另外在构造方法里我给出了两个参数,一个是需要留下来的属性名,通过数组传递,另一个是一个Class<?> type,也是相关上面说到例子中的Organzition.class,是用来在后面通过该class调用java反射机制获取属性值,在取到相关属值后组装成字符串,最后通过JSONObject.fromObject来输出,不这样输出会有问题,至于什么问题,有好奇心的同学自己试试

    下面是调用方法:

    Java代码  收藏代码
    1. jsonConfig.registerJsonValueProcessor(Organzition.class,   
    2.        new ObjectJsonValueProcessor(new String[]{"orgName","orgId"},Organzition.class));  

     

    其中,Organzition.class是你要处理的属性类型

  • 相关阅读:
    Java 流程控制语句 之 顺序结构
    CSS 滑动门案例
    CSS 精灵技术(sprite)
    【剑指Offer-代码的鲁棒性】编程题23:链表中环的入口节点
    【剑指Offer-代码的鲁棒性】面试题22:链表中倒数第k个节点
    【剑指Offer-代码的完整性】面试题21:调整数组顺序使奇数位于偶数前面
    【剑指Offer-代码的完整性】面试题20:表示数值的字符串
    【剑指Offer-代码的完整性】面试题19:正则表达式匹配
    【剑指Offer-代码的完整性】面试题16:数值的整数次方
    【剑指Offer-位运算】面试题15:二进制中1的个数
  • 原文地址:https://www.cnblogs.com/zjhs/p/3007535.html
Copyright © 2011-2022 走看看