-1

I have following problem. I'm new to Spring. I have created 2 entities and now using postman I want to get all books but I keep getting StackOverflowError.

Here is book model

package com.example.demo;

import jakarta.persistence.*;

import java.util.List;

@Entity
public class BookEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String title;
    @ManyToMany
    private List<Author> author;

    public BookEntity() {
    }

    public BookEntity(String title) {
        this.title = title;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Author> getAuthor() {
        return author;
    }

    public void setAuthor(List<Author> author) {
        this.author = author;
    }
}

Author class model

package com.example.demo;

import jakarta.persistence.*;

import java.util.List;

@Entity
public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;
    @ManyToMany
    private List<BookEntity> book;

    public Author() {
    }

    public Author(String name) {
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<BookEntity> getBook() {
        return book;
    }

    public void setBook(List<BookEntity> book) {
        this.book = book;
    }
}

repository for books

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRepository extends JpaRepository<BookEntity, Long> {
}

repository for author

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
}

controller for books

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {

    private final AuthorRepository authorRepository;
    private final BookRepository bookRepository;

    public BookController(AuthorRepository authorRepository, BookRepository bookRepository) {
        this.authorRepository = authorRepository;
        this.bookRepository = bookRepository;
    }

    @GetMapping
    List<BookEntity> getAllBooks() {
        return bookRepository.findAll();
    }
}

Can you please explain what is happening? I can't get any further. I'm stuck

  • 1
    https://stackoverflow.com/questions/17393812/json-and-java-circular-reference Book -> Author ->Book-> Author ->Book-> Author ->Book-> Author ->Book ->.... – Shakirov Ramil Feb 09 '23 at 14:59
  • thank you, references helped. I will read about dto :) –  Feb 09 '23 at 15:18

1 Answers1

1

Well this is a common issue. The problem is that you have Book and Author related as ManyToMany. So now whenever you reach for Books, they have an Author field, and when Jackson is trying to add Author it turns out that Author has Books which again have an Author.

Im am aware of 2 ways out of here. First one is DTO you should create a class to be displayed by you controller looking somewhat like this:

public class BookDTO {
    private long bookId;
    private String bookTitle;
    private List<AuthorDTO> authors;
// constructors getters setters

}

situation is a bit complicated because of Many to many so yo need another DTO for authors

public class AuthorDTO {
    private long authorId;
    private String authorName;
//constructors getters setters
}

you could use a service layer to do all of the mapping. Then you should return BookDTO in your controller.

Another way out are annotations:

    @ManyToMany
    @JsonManagedReference
    private List<Author> author;

and

    @ManyToMany
    @JsonBackReference
    private List<BookEntity> book;

@JsoonManaged and back References will stop Jackson from digging into another entity.

Another thing is you should consider mappedBy in one of your Entities to prevent creating 2 tables.

Pioter88
  • 133
  • 1
  • 6