中间表上杰克逊的无限递归

Posted

技术标签:

【中文标题】中间表上杰克逊的无限递归【英文标题】:Infinite recursion with Jackson on intermediate table 【发布时间】:2021-01-24 10:02:45 【问题描述】:

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

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

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

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


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


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

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (***Error); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (***Error) (through reference chain: java.util.ArrayList[0]->com.exampleAPI.api.model.Book["written"])]

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

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

有人可以帮我吗?

【问题讨论】:

类似问题:Jackson serialize problem in @ManyToMany relationship, Jackson/Hibernate, meta get methods and serialization 【参考方案1】:

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

我尝试在 Written 类中使用 @JsonIgnore、@JsonManagedReference 和 @JsonBackReference

您需要单独使用@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,但ModelMapper 也是一种选择。如果此类实体的数量较少,则使用构造函数/getter/setter 就足够了。

【讨论】:

哦,非常感谢,但繁殖行为并不完全符合预期。我现在可以检索书籍及其信息(不再有无限递归错误),但没有作者的踪迹或存储在 Written 中的其他字段。有什么建议吗? @nicooooo 使用映射库仅映射书籍的“第一”层,而无需进一步参考作者。 我提前道歉,但这是我在这个领域的第一个应用程序,我不知道该怎么做 没关系。为简单起见,除非您真的需要它们,否则不要使用双向关系。有关 entity-to-dto-mapping 的更多信息,请在 Google 上搜索此术语:MapStruct entity to dto,您会发现大量教程可供开始。

以上是关于中间表上杰克逊的无限递归的主要内容,如果未能解决你的问题,请参考以下文章

高级双向杰克逊序列化以避免无限递归

Azure,中间表上的聚集索引和性能影响

杰克逊 JSON、Spring MVC 4.2 和 Hibernate JPA 问题的无限递归

更新中间表Laravel关系

从数据结构中间层中剔除值

二分查找递归版以及书写递归的注意事项