Infinite Recursion With Jackson Json and Hibernate JPA Issue

Infinite Recursion with Jackson JSON and Hibernate JPA issue

You may use @JsonIgnore to break the cycle (reference).

You need to import org.codehaus.jackson.annotate.JsonIgnore (legacy versions) or com.fasterxml.jackson.annotation.JsonIgnore (current versions).

Infinite recursion with Jackson on intermediate table

When unhandled bidirectional relationship occurs, Jackson faces infinite recursion.

I tried to use @JsonIgnore, @JsonManagedReference and @JsonBackReference on the Written class

You need to use @JsonManagedReference and @JsonBackReference annotations separately to prevent these cycles between Book and Written. A side note, transient has nothing to do with the persistence but the serialization. JPA works with the @Transient annotation.

public class Book implements Serializable {

@OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
@JsonBackReference
private Set<Written> written= new HashSet<>();

...
}
public class Written implements Serializable {

@Id
@ManyToOne
@JoinColumn(name = "idBook")
@JsonManagedReference
private Book book;

...
}

Important: Don't send database entities through REST (probably what you are up to do). Better create a DAO object without bidirectional relationship and map entities into DAOs. There are several libraries able to do that: I highly recommend MapStruct, however ModelMapper is also an option. If there is a lower number of such entities, using constructors/getters/setters would be enough.

Infinite Recursion with Jackson JSON and Hibernate JPA

You need to use @JsonManagedReference and @JsonBackReference to allow Jackson to better handle the relationship between Author and Book:

public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer author_id;
private String name;
private String language;

@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Set<Book> book;

// getter setter
}
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;

@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;

// getter setter
}

You have other options (e.g. using @JsonIdentityInfo) to handle this infinite recursion issue, but this is the most common solution. You can check all other possible approaches at the following online resource https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.


Additionally, in your Service you are creating a brand new Book and setting its title with book.setTitle(book.getTitle());, which basically does nothing. In fact you don't even need to do most of the stuff you are doing there because Book instances are already in Author, you just need to set Author on each Book instance as follows:

@Override
public Author insertAuthor(Author author) {
for (Book book : author.getBook()) {
book.setAuthor(author);
}

return authorRepo.save(author);
}

Finally, consider changing the book property in Author to books since it contains multiple books (you will need to adjust your code afterwards).

Infinite Recursion with JSON and Hibernate JPA

The problems occurs because there is an infinite loop when generating the JSON. You can use @JsonManagedReference and @JsonBackReference to solve the Infinite recursion.

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Project implements Serializable{

@Id @GeneratedValue
private long id;
private String intitule;
private String description;

@OneToMany(mappedBy = "project" , fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
@JsonIgnoreProperties("contrats")
private Collection<Contrat> contrats;

@ManyToOne
@JoinColumn(name = "Id_appUser")
@JsonBackReference
private AppUser appUser;
}

AppUser

@Entity
@Data
@AllArgsConstructor @NoArgsConstructor
public class AppUser implements Serializable {

@Id @GeneratedValue
private Long id;
@Column(unique = true)
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Collection<AppRole> roles = new ArrayList<>();

@OneToMany(mappedBy = "appUser" , fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
@JsonManagedReference
private Collection<Project> projects = new ArrayList<>();


@OneToMany(mappedBy = "appUser" , fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private Collection<Intervention> interventions = new ArrayList<>();

@OneToMany(mappedBy = "appUser" , fetch = FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private Collection<Contrat> contrats = new ArrayList<>();

}

Could not write JSON: Infinite recursion

More than one of your entities have each other in themselves.
For example, Product has an object of User, and User has an object of Product.

To solve this, you have to write

@JsonBackReference(value = "user-product")
private User user;

in the Product class,
and

@JsonManagedReference(value = "user-product")
private Product product;

In the user class.
Do it in every field and for every class that call each other.

Also, Check this out
JPA: Having lists on both ends without infinite loop

Could not write JSON:Infinite recursion(StackOverflowError)nested exception is com.fasterxml.jackson.databind.JsonMappingException:Infinite recursion

I simply added @JsonIgnore and it working.

@OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
@JsonIgnore
private Set<Employee> employees;

also

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DEPT_ID", nullable = false)
@JsonIgnore
private Department department;

Infinite Recursion with Jackson JSON, Spring MVC 4.2 and Hibernate JPA issue

Just put @JsonIgnore

@JsonIgnore
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userClass")
public List<User> getUsers() {
return this.users;
}

This will ignore lazy load object and fix your issue.

Update

  • According to Udara Seneviratne answer, You can handle bi-directional relationship by @JsonManagedReference, @JsonBackReference.


Related Topics



Leave a reply



Submit