'Infinite Recursion with Jackson JSON and Hibernate JPA

I want to store some data into database through OnetoMany and ManytoOne Bidirectional relationship mapping. While request for persist data in postman get infinite row in response.

Here down is my code:

Entity

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

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

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

    // getter setter
}

Service

@Override
public Author insertAuthor(Author author) {
        Set<Book> bookList = new HashSet<>();
        
        Book book = new Book();
        book.setTitle(book.getTitle());
        
        bookList.add(book);
        
        book.setAuthor(author);
        author.setBook(bookList);
        
        return authorRepo.save(author);
}

Controller

@RestController
public class PojoController {
    
    @Autowired
    private PojoService pojoService;
    
    @RequestMapping(value="/book", method = RequestMethod.POST)
    public Author addBookCourse(@RequestBody Author author) {
        return this.pojoService.insertAuthor(author);
    }
}

Request

{
    "language": "english",
    "name": "Banjamin franklin",
    "book": [{
        "title": "Theory Of Everything"
    },
    {
        "title": "A Brief Story Of Time"
    }]
}

Output

{
    "author_id": 1,
    "name": "Banjamin franklin",
    "language": "english",
    "book": [
        {
            "id": 1,
            "title": null,
            "author": {
                "author_id": 1,
                "name": "Banjamin franklin",
                "language": "english",
                "book": [
                    {
                        "id": 1,
                        "title": null,
                        "author": {
                            "author_id": 1,
                            "name": "Banjamin franklin",
                            "language": "english",
                            "book": [
                                {
                                    "id": 1,
                                    "title": null,
                                    "author": {
                                        "author_id": 1,
                                        "name": "Banjamin franklin",
                                        "language": "english",
                                        "book": [
                                            {
                                                "id": 1,
                                                "title": null,
                           more 7460 line
                           .......
                           .......
                           .......
{
    "timestamp": "2021-11-30T10:25:03.957+00:00",
    "status": 200,
    "error": "OK",
    "trace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]->com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]
}    


Solution 1:[1]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1