Jackson 在中间 table 上的无限递归

Infinite recursion with Jackson on intermediate table

我正在使用 Spring Boot、Jackson 和 Hibernate 创建一个 API。 Hibernate 连接到 MySQL 数据库。 我了解良好做法,但我坚持一个特定的观点。 我有一个包含额外字段的 n:m 关系。

例如:作者(id, ...) -> 书面(idAuthor, idBook, 日期) <- 书(id, ...)

我了解如何映射传统的 n:m 关系,但这次该技术不适用于我。

为此,我在互联网上找到了一个显示解决方案的来源:在我的代码中创建一个中间体 class,其中包含作者类型对象和书籍类型对象 + 我的附加字段。


@Entity
@Table(name = "Author")
public class Author implements Serializable {
/...
 
    @Id
    @GeneratedValue
    private int id;

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

@Entity
@Table(name = "Book")
public class Book implements Serializable{
/...

    @Id
    @GeneratedValue
    private int id;

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


public class Written implements Serializable {

    @Id
    @ManyToOne
    @JoinColumn(name = "idAuthor")
    private Author author;

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

    //Extra fields ....

}

这是双向的 link。 使用此代码,我得到一个无限递归错误:

Resolved [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: java.util.ArrayList[0]->com.exampleAPI.api.model.Book["written"])]

我尝试在 Written class 上使用 @JsonIgnore@JsonManagedReference@JsonBackReference,也尝试使用 transient 关键字,但没有任何效果。

我在 Internet 上找不到任何可以帮助我的资源,也找不到针对此特定案例的文档。

有人可以帮助我吗?

当出现未处理的双向关系时,杰克逊面临无限递归。

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

您需要使用 @JsonManagedReference@JsonBackReference 注释 分开 来防止 BookWritten 之间的这些循环。旁注,transient 与持久性无关,而与序列化有关。 JPA 使用 @Transient 注释。

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;

    ...
}

重要提示:不要通过 REST 发送数据库实体(可能是您要做的)。最好创建一个没有双向关系 的 DAO 对象 并将实体映射到 DAO。有几个库可以做到这一点:我强烈推荐 MapStruct, however ModelMapper 也是一个选项。如果此类实体的数量较少,则使用 constructors/getters/setters 就足够了。