If you’re using Object Relational Mapping frameworks like Hibernate, and are using the bi-directional mappings then you can be sure of getting the following errors if you try to generate JSON of the entities involved.
1. If you’re using Jackson
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)
2. If you’re using Google’s Gson
java.lang.IllegalStateException: circular reference error
Let’s take a case of two entities Actor, and Movie having a bi-directional relationship and using them we’ll see how to get over the above exceptions when we try to generate JSON.
This solution uses Jackson for generating JSON.
So if you’re using Google’s Gson you’ll have to write an exclusion strategy yourself, and more importantly the rest of the post is useless for you, unless you’re willing to switch to Jackson like I did with such great finesse! 😉
If yes, then you can download Jackson’s libraries and continue reading the post further, rest assured that it’ll be of immense help to you! 🙂
Now, these entities will have a many-to-many relationship amongst them. As one Actor can act in many Movies and one Movie can have many Actors (as it so often happens, and by the way due apologies for being trite and rhetoric!).
Actor.java
@Entity @Table(name="Actor") public class Actor implements Serializable { . . . /* This is the exception-saving-annotation */ @JsonManagedReference @ManyToMany private List<Movie> movies; . . . }
Movie.java
@Entity @Table(name="Movie") public class Movie implements Serializable { . . . /* This is the exception-saving-annotation */ @JsonBackReference @ManyToMany(mappedBy="movies") private List<Actor> actors; . . . }
So all we did was adding two annotations to the fields having a relationship.
- @JsonManagedReference: This annotation should be put on the owner of the relationship, or as you may deem fit.
- @JsonBackReference: This annotation should be used on the other end of the relationship.
Now, having done that it’s extremely easy to generate the JSON.
//com.fasterxml.jackson.databind.ObjectMapper ObjectMapper objectMapper = new ObjectMapper(); //The input argument of the writeValueAsString() function can be a bean, array, list, map or a set. String actorsAsJson = objectMapper.writeValueAsString(actorsList); //actorsList is a variable of type List<Actor> //Voila! You're done!
That’s all for the circular dependency errors.
~ Entity Class Code Snippets by Amit
I cannot imagine how your code works — I have a similar situation and an exception is thrown saying that back reference cannot be a list. Actually the javadoc of JsonBackreference class also clearly states this
” * Annotation used to indicate that associated property is part of
* two-way linkage between fields; and that its role is “child” (or “back”) link.
* Value type of the property must be a bean: it can not be a Collection, Map,
* Array or enumeration.”
LikeLike
Using Gson you can use GraphAdapterBuilder
http://code.google.com/p/google-gson/source/browse/trunk/extras/src/main/java/com/google/gson/graph/GraphAdapterBuilder.java?r=1117
LikeLike
Hi, i have a problem. I have implemented that into my entities and everything works fine, except for one entity. It has a @ManyToMany relation unidireccional(not bidiretional) to the same entity and I always get circular error. can you help me?
LikeLike
Hi, I couldn’t get your problem. You are saying you have an entity and that entity has in turn reference to the same entity. But why would you have @ManytoMany on the same entity? Isn’t that used to define the relation with some other entity?
LikeLike
Hi, I have a entity call “User” and a ‘user’ has many friends(other users). so I put a @ManyToMany relation, I wrote to Set’s into de entity “User” to make a bidireccional relation and that resolve the cycle problem, but when I try to get a ‘user’ whitout his friends i always obtain the ‘user’ and all his relations “fiends, and other things”.
is there a way that if i call just the ‘user’ just get the ‘user’? and not all the relations?
I have my relations defiend with Lazy scope.
LikeLike
I still think you don’t need a @ManyToMany relation there. Can you please post your entity class code snippet please?
As you would do that in a case of self referencing as in Employee-Manager.
public class Employee {
…
@ManyToOne
private Employee manager;
@OneToMany(mappedBy=”manger”)
private Set reportees;
…
}
See here you have two kinds of relations one Manager and the other his Reportees. But in your case i.e. User has many friends.
So just having a set friends would suffice I guess.
LikeLike
Quite a handy code. Will be using it very soon! And yes! thanks for the credit ! 😛
LikeLike
Thank you! And as far as credit is concerned you only introduced me to JSON. 😉
LikeLike