A little insight into the problem of Json+hibernate cycle

Source: Internet
Author: User
Tags getmessage

"Problem" title, when we use the Hibernate framework and need to convert objects to JSON, if we configure a two-way correlation, this is a dead loop problem

Exception information:

Why does this happen? The reason is that the object you are converting is configured with an association to another object, and that object is configured with an association to your object. For example, my two classes are called Shop (store) and staff (employees), a store can have more than one employee, so I have configured two-way bi-and many-to-one relationship. The problem arises when JSON Lib transforms the shop object into a JSON string and discovers that there is a set<staff> in it, and that it will cascade the set<staff> into a JSON string, when it iterates through the set , found that there is a shop object in the staff, this time it will try to convert shop into a JSON string, and then found that there are set<staff>, so the cycle, the formation of a dead cycle.

1Method PublicJava.lang.String Org.apache.commons.lang.exception.NestableRuntimeException.getMessage (int) threw an exception when invoked on Net.sf.json.JSONException:There are a cycle in the hierarchy!2 The problematic instruction:3----------4==> ${msgs[0][0]} [on line, column, org/apache/struts2/dispatcher/ERROR.FTL]5----------6   7Java BackTrace forProgrammers:8----------9Freemarker.template.TemplateModelException:Method PublicJava.lang.String Org.apache.commons.lang.exception.NestableRuntimeException.getMessage (int) threw an exception when invoked on Net.sf.json.JSONException:There are a cycle in the hierarchy!TenAt Freemarker.ext.beans.SimpleMethodModel.exec (simplemethodmodel.java:130)   OneAt Freemarker.ext.beans.SimpleMethodModel.get (simplemethodmodel.java:138)   AAt Freemarker.core.DynamicKeyName.dealWithNumericalKey (dynamickeyname.java:111)   -At Freemarker.core.dynamickeyname._getastemplatemodel (dynamickeyname.java:90)   -At Freemarker.core.Expression.getAsTemplateModel (expression.java:89)   theAt Freemarker.core.Expression.getStringValue (expression.java:93)   -At Freemarker.core.DollarVariable.accept (dollarvariable.java:76)   -At Freemarker.core.Environment.visit (environment.java:209)   -At Freemarker.core.MixedContent.accept (mixedcontent.java:92)   +At Freemarker.core.Environment.visit (environment.java:209)   -At Freemarker.core.IfBlock.accept (ifblock.java:82)   +At Freemarker.core.Environment.visit (environment.java:209)   AAt Freemarker.core.IfBlock.accept (ifblock.java:82)   atAt Freemarker.core.Environment.visit (environment.java:209)   -At Freemarker.core.MixedContent.accept (mixedcontent.java:92)   -At Freemarker.core.Environment.visit (environment.java:209)   -At Freemarker.core.Environment.process (environment.java:189)   -At Freemarker.template.Template.process (template.java:237)   -At Org.apache.struts2.dispatcher.Dispatcher.sendError (dispatcher.java:748)   inAt Org.apache.struts2.dispatcher.Dispatcher.serviceAction (dispatcher.java:505)   -At Org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction (executeoperations.java:77)   toAt Org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter ( strutsprepareandexecutefilter.java:91)   +At Org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (applicationfilterchain.java:235)   -At Org.apache.catalina.core.ApplicationFilterChain.doFilter (applicationfilterchain.java:206)   theAt Org.apache.catalina.core.StandardWrapperValve.invoke (standardwrappervalve.java:233)   *At Org.apache.catalina.core.StandardContextValve.invoke (standardcontextvalve.java:191)   $At Org.apache.catalina.core.StandardHostValve.invoke (standardhostvalve.java:127)  Panax NotoginsengAt Org.apache.catalina.valves.ErrorReportValve.invoke (errorreportvalve.java:103)   -At Org.apache.catalina.core.StandardEngineValve.invoke (standardenginevalve.java:109)   theAt Org.apache.catalina.connector.CoyoteAdapter.service (coyoteadapter.java:293)   +At Org.apache.coyote.http11.Http11Processor.process (http11processor.java:861)   AAt Org.apache.coyote.http11.http11protocol$http11connectionhandler.process (http11protocol.java:606)   theAt Org.apache.tomcat.util.net.jioendpoint$worker.run (jioendpoint.java:489)   +At Java.lang.Thread.run (thread.java:619)   - caused By:java.lang.NullPointerException $At Freemarker.ext.beans.SimpleMemberModel.unwrapArguments (simplemembermodel.java:85)   $At Freemarker.ext.beans.SimpleMethodModel.exec (simplemethodmodel.java:106)   -... More

"Solve" The problem is clear, how to solve it? I Baidu a bit, also found dozens of of information, but mostly just explained to use Jsonconfig.setjsonpropertyfilter (new PropertyFilter () {}), and for the parameters and if statements in which to write, There is no one to say very clearly. For this I looked at the source code of Json-lib, and made a trial, summarized as follows:

1, the idea is to jsonobject the shop object into a JSON string, in the middle of adding a filter, if the current property to be converted is set and the property name is staffs, then filter

2, the code is as follows:

Map<string, object> map=NewHashmap<string, object>(); Map.put ("Shops", list); Map.put ("Total", total); Jsonconfig Jsonconfig=NewJsonconfig (); Jsonconfig.setjsonpropertyfilter (NewPropertyFilter () { Public Booleanapply (Object obj, String name, Object value) {if(ValueinstanceofSet<?>&&name.equals ("Staffs")){          return true; }Else{          return false;            }     }  }); returnJsonobject.fromobject (Map,jsonconfig);

As above, PropertyFilter is an interface for property filtering provided by Json-lib, the implementation is done by the Apply method, then we need to rewrite the Apply method.

This method has three parameters, the first is object type, and is the type of objects you want to convert (shop);

The second argument is a string type, which is the name of the property you want to filter;

The third parameter is the object type, which is the value of the property you want to filter (the value may be string or other type, so use object).

The return value is Boolean, returns True, is filtered, returns false, and is not filtered.

If the wording of the statement will be based on the actual need, for example, I have to solve the death cycle here, it is necessary to implement the Set<staff> staffs property in the shop filter out, then my if statement should be as above written. All in all, Json-lib will call this apply method on each property when it is transformed, so that we are going to return true if the current attribute matches your if condition according to the actual business need. is to use | | && also depends on the actual.

After this configuration, and then test, we found that the time to get shop is dead cycle problem no longer appear.

3, similarly, the staff side should also have similar configuration

Map<string,object> map=NewHashmap<string, object>(); Map.put ("Staffs", list); Map.put ("Total", total); Jsonconfig Jsonconfig=NewJsonconfig (); Jsonconfig.setexcludes (Newstring[]{"Handler", "Hibernatelazyinitializer"}); Jsonconfig.setjsonpropertyfilter (NewPropertyFilter () { Public Booleanapply (Object obj, String name, Object value) {if(Name.equals ("Shop"))){              return true; }Else{              return false;            }      }  }); returnJsonobject.fromobject (Map,jsonconfig);

After testing, there is no problem.

Here you can also see Jsonconfig.setexcludes (New string[]{"Handler", "Hibernatelazyinitializer"}); This line is set to prevent Hibernate from delaying the exception caused by the load.

4, are you done here? No, I found a more serious problem in the test, if I follow the above configuration, then I get shop, the generated JSON string in the staffs set is missing, when the staff, its property shop in the JSON string is also missing! A little analysis will tell you that this is the result of the above configuration. According to the above configuration, shop in the set<staff> is filtered out, "filter out" meaning is not a cascade of conversion staff in the shop, but directly even set<staff> are not converted. This is bad, I configure the two-way association is to associate the display, you have my attributes filtered out, then I also configure a bidirectional association why? What the hell am I going to do with the dead loop?

So how do we solve this problem? In fact, it is not difficult to think carefully, we look at the shop's configuration to change to the following

Map<string, object> map=NewHashmap<string, object>(); Map.put ("Shops", list); Map.put ("Total", total); Jsonconfig Jsonconfig=NewJsonconfig (); Jsonconfig.setjsonpropertyfilter (NewPropertyFilter () { Public Booleanapply (Object obj, String name, Object value) {if(ValueinstanceofShop&&name.equals ("Shop")){          return true; }Else{          return false;            }     }  }); returnJsonobject.fromobject (Map,jsonconfig);

So you can get it, why? Because of this configuration, in the shop in the set<staff> staffs conversion, we do not filter, and in the staffs in each staff in the shop conversion, we filter, so that both solve the death cycle problem, It also avoids the problem that the staffs in the shop is filtered out.

Similarly, the staff should be configured like this

Map<string,object> map=new hashmap<string, object> ();  Map.put ("Staffs", list);  Map.put ("Total", total);            Jsonconfig jsonconfig = new Jsonconfig ();    Jsonconfig.setexcludes (New string[]{"Handler", "Hibernatelazyinitializer"});  Jsonconfig.setjsonpropertyfilter (New PropertyFilter () {public         Boolean apply (Object obj, String name, object value) {          if (name.equals ("Staffs")) {              return true;          } else{              return false;}}  );            Return Jsonobject.fromobject (Map,jsonconfig);  

But when I was testing, I found out that only total,staffs was in the string. As you can see, not only the staffs in the shop are filtered out, but the staffs in the map is also filtered out. The solution is also very simple, put map.put ("Staffs", list), change to Map.put ("list", list), just go, just change a name.

"Extension" here, should be able to solve the problem of everyone. There is another way to mention it,

1 New jsonconfig ();   2 jsonconfig.setignoredefaultexcludes (false// Set default Ignore    3 Jsonconfig.setcycledetectionstrategy (cycledetectionstrategy.lenient); // set the looping policy to ignore the    problem of solving json most headaches  of the dead loop 4 jsonconfig.setexcludes (new string[] {" Staffs "}); // here is the highlight, as long as you add the desired ignore field to  the array

This configuration is also relatively good understanding, but also pay attention to attribute filtering problems, shop filter Shop,staff filter staffs.

This article is reproduced from http://blog.csdn.net/superick/article/details/19421145

A little insight into the json+hibernate of the dead loop problem

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.