When trying to convert a JPA object that has a bi-directional association into JSON, I keep getting
org.codehaus.jackson.map.JsonMappingException: Infinite
You can now use JsonIgnoreProperties to suppress serialization of properties (during serialization), or ignore processing of JSON properties read (during deserialization). If this is not what you're looking for, please keep reading below.
(Thanks to As Zammel AlaaEddine for pointing this out).
Since Jackson 1.6 you can use two annotations to solve the infinite recursion problem without ignoring the getters/setters during serialization: @JsonManagedReference and @JsonBackReference.
Explanation
For Jackson to work well, one of the two sides of the relationship should not be serialized, in order to avoid the infite loop that causes your stackoverflow error.
So, Jackson takes the forward part of the reference (your Set
in Trainee class), and converts it in a json-like storage format; this is the so-called marshalling process. Then, Jackson looks for the back part of the reference (i.e. Trainee trainee
in BodyStat class) and leaves it as it is, not serializing it. This part of the relationship will be re-constructed during the deserialization (unmarshalling) of the forward reference.
You can change your code like this (I skip the useless parts):
Business Object 1:
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
@JsonManagedReference
private Set bodyStats;
Business Object 2:
@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
@JsonBackReference
private Trainee trainee;
Now it all should work properly.
If you want more informations, I wrote an article about Json and Jackson Stackoverflow issues on Keenformatics, my blog.
EDIT:
Another useful annotation you could check is @JsonIdentityInfo: using it, everytime Jackson serializes your object, it will add an ID (or another attribute of your choose) to it, so that it won't entirely "scan" it again everytime. This can be useful when you've got a chain loop between more interrelated objects (for example: Order -> OrderLine -> User -> Order and over again).
In this case you've got to be careful, since you could need to read your object's attributes more than once (for example in a products list with more products that share the same seller), and this annotation prevents you to do so. I suggest to always take a look at firebug logs to check the Json response and see what's going on in your code.
Sources: