In a rest application, I use spring boot with jpa.
I have a class Lodger
who have
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
In my class Reference, i have
@ManyToOne
@JoinColumn(name = "lodgerId")
private Lodger lodger;
when i call this method
@RequestMapping(value = "/lodgers/{lodgerId}", method = RequestMethod.GET)
public Lodger getLogderById(@PathVariable("lodgerId") long lodgerId) {
return lodgerService.getLodger(lodgerId);
}
I get this error
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]...
Solution:
Use
@JsonManagedReference
annotation for the first objects instantiated
@JsonBackReference
annotation for the second objects instantiated
First:
@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
Second:
@JsonBackReference
@ManyToOne
@JoinColumn(name = "lodgerId")
private Lodger lodger;
Do not return entity with circular dependencies via REST webservice - create new DTO class, map entities fetched from database and return it in webservice.
More info here: http://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
Of course if you want you may use another mapping library, my personal favourite is Orika (http://orika-mapper.github.io/orika-docs/intro.html)
If you primary keys in both tables are same name for example : id.
Add this
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
...
}
And to Reference class.
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Reference {
...
}
The only thing that you need is, in your class in which you have the annotation @ManyToOne
, implement the next annotation with the attributes that you want to skip in the value section
@JsonIgnoreProperties(value = {"yourAttribute", "handler", "hibernateLazyInitializer"}, allowSetters = true)
I put an example for your code ->
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties(value = {"referenceList", "handler","hibernateLazyInitializer"}, allowSetters = true)
@JoinColumn(name = "lodgerId")
private Lodger lodger;
All the attributes that you put in the value section on the @JsonIgnoreProperties
are ignored, with this you can resolve the infinite loop and use it for other developments with the same format in the future.
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