Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite loop with spring-boot in a one to many relation

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"]...
like image 391
robert trudel Avatar asked Jun 17 '15 12:06

robert trudel


4 Answers

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;
like image 132
btd1337 Avatar answered Sep 22 '22 02:09

btd1337


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)

like image 31
mdziob Avatar answered Sep 21 '22 02:09

mdziob


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 {
    ...
}
like image 22
VK321 Avatar answered Sep 21 '22 02:09

VK321


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.

like image 21
Juan Carlos Guerrero Moyano Avatar answered Sep 18 '22 02:09

Juan Carlos Guerrero Moyano