Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC REST JPA Hibernate Jackson infinite recursion one-to-many JSON error

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?

like image 741
hamo Avatar asked Jan 17 '14 03:01

hamo


People also ask

How do you stop infinite recursion?

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.

What is @JsonManagedReference and @JsonBackReference?

@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.

What is @JsonIdentityInfo?

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.

What is the use of @JsonBackReference?

@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.


1 Answers

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.

like image 58
hamo Avatar answered Sep 27 '22 23:09

hamo