I have a one to many bi-directional relationship between a parent
entity and child
entities(ie.parent has one or more children and child has only one parent) in a Spring MVC REST Service which uses JPA and Hibernate for persistence.
Whenever I try to return a list of the parent entities in JSON, I get something like as follows in an infinite loop:
[{"businessName":"Cake Shop","businessDescription":"We sell cakes","businessId":1,"promotions":[{"name":"Cake Sale","id":1,"description":"Get free cakes","business":{"businessName":"Cake Shop","businessDescription":"We sell cakes","businessId":1,"promotions":[{"name":"Cake Sale","id":1,"description":"Get free cakes","business"
with the following error:
com.fasterxml.jackson.databind.JsonMappingException:
Infinite recursion (StackOverflowError)
Below is my controller:
@RequestMapping(value="/getBusinesses", method = RequestMethod.GET)
@ResponseBody
public List<Business> getAllBusinessTypes(){
List<Business> businesses = businessService.findAllBusinesses();
return businesses;
}
and my 2 entities are:
@Entity
public class Business implements Serializable{
@Id
@GeneratedValue
private Long businessId;
private String businessName;
private String businessDescription;
@OneToMany(mappedBy = "business", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Promotion> promotions = new ArrayList<Promotion>();
public String getBusinessDescription() {
return businessDescription;
}
public void setBusinessDescription(String businessDescription) {
this.businessDescription = businessDescription;
}
public String getBusinessName() {
return businessName;
}
public void setBusinessName(String businessName) {
this.businessName = businessName;
}
public Long getBusinessId() {
return businessId;
}
public void setBusinessId(Long businessId) {
this.businessId = businessId;
}
public List<Promotion> getPromotions() {
return promotions;
}
public void setPromotions(List<Promotion> promotions) {
this.promotions = promotions;
}
}
and
@Entity
@Table(name = "promotions")
public class Promotion implements Serializable{
@Id
@GeneratedValue
private Long id;
@ManyToOne
private Business business;
private String name;
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Business getBusiness() {
return business;
}
public void setBusiness(Business business) {
this.business = business;
}
}
I have Jackson included, should it not automatically convert the JSON or am I being stupid and missing something obvious?
To prevent infinite recursion, you need at least one branch (i.e. of an if/else statement) that does not make a recursive call. Branches without recursive calls are called base cases; branches with recursive calls are called recursive cases. Functions can also be mutually recursive.
@JsonManagedReference is the forward part of reference, the one that gets serialized normally. @JsonBackReference is the back part of reference; it'll be omitted from serialization.
The @JsonIdentityInfo annotation is used when an object has a parent-child relationship in the Jackson library. The @JsonIdentityInfo annotation is used to indicate the object identity during the serialization and deserialization process.
@JsonManagedReferences and JsonBackReferences are used to display objects with parent child relationship. @JsonManagedReferences is used to refer to parent object and @JsonBackReferences is used to mark child objects.
I found the solution here
http://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html
https://fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonBackReference.html
I had to add @JsonManagedReference annotation to the getter for my List of promotions in my Business object(the 'one' in my OneToMany relationship) like so:
@Entity
public class Business implements Serializable{
...
@JsonManagedReference
public List<Promotion> getPromotions() {
return promotions;
}
and @JsonBackReference to the getter for my business object in my Promotion object(the 'many' in my OneToMany relationship) like so:
@Entity
public class Promotion {
...
@JsonBackReference
public Business getBusiness() {
return business;
}
It seems this type of bi-directional relationship causes a serialization problem with Jackson.
Also Jackson 1.6 or higher must be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With