【问题标题】: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 (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.exampleAPI.api.model.Book["written"])]

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

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

有人可以帮我吗?

【问题讨论】:

标签: java spring-boot hibernate jackson


【解决方案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,您会发现大量教程可供开始。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
相关资源
最近更新 更多