Jackson JSON 和 Hibernate JPA 的无限递归

Infinite Recursion with Jackson JSON and Hibernate JPA

我想通过 OnetoManyManytoOne 双向关系映射将一些数据存储到数据库中。虽然在邮递员中请求持久数据得到无限行响应。

下面是我的代码:

实体

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
}

服务

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

控制器

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

请求

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

输出

{
    "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 (WhosebugError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (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\"]
}    

你需要使用@JsonManagedReference@JsonBackReference来让Jackson更好地处理AuthorBook之间的关系:

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
}

您还有其他选择(例如使用 @JsonIdentityInfo)来处理这个无限递归问题,但这是最常见的解决方案。您可以在以下在线资源 https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.

中查看所有其他可能的方法

此外,在您的服务中,您正在创建一个全新的 Book 并将其标题设置为 book.setTitle(book.getTitle());,这基本上什么都不做。事实上,你甚至不需要做你在那里做的大部分事情,因为 Book 个实例已经在 Author 中,你只需要在每个 Book 上设置 Author ]实例如下:

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

最后,考虑将Author中的book属性改成books,因为它包含多本书(之后你需要调整你的代码)。