Home > Software engineering >  Why reference to the foreign key pass multiple time in restapi
Why reference to the foreign key pass multiple time in restapi

Time:12-01

I want to store some data into database through One to Many and Many to One Bidirectional relationship mapping but while request for persist data post insert 7460 line. I can googling but not found proper solution.

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\"]
}    

CodePudding user response:

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

  • Related