JPA 多对多关系导致无限递归和堆栈溢出错误
JPA many-to-many relationship causing infinite recursion and stack overflow error
我正在开发一个 EclipseLink 项目,其中一个用户可以 "follow" 另一个用户,就像在社交媒体网站上一样。我设置了一个 User
实体(引用一个名为 users
的 table),它有一个列表 "followers"(关注该用户的用户)和另一个列表 "following"(用户关注的用户)。该关系在名为 followers
的单独 table 中定义,其中包含关注用户 ID (user_id
) 和关注用户 ID (follower_id
) 的列。
我的用户模型如下所示:
@Entity
@Table(name = "users")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM USER u")
public class User {
// other attributes
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "follower", joinColumns = @JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "follower_id", referencedColumnName = "id"))
private List<User> followers;
@ManyToMany(mappedBy = "followers")
private List<User> following;
// other getters and setters
public List<User> getFollowers() {
return this.followers;
}
public List<User> getFollowing() {
return this.following;
}
}
getFollowers()
方法似乎工作正常,但是当调用 getFollowing()
时,我收到一堆控制台垃圾邮件,最终导致 WhosebugException:
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion
(WhosebugError) (through reference chain:
org.eclipse.persistence.indirection.IndirectList[0]-
>org.myproject.model.User["followers"]-
>org.eclipse.persistence.indirection.IndirectList[0]-
>org.myproject.model.User["following"]-
...
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase
.serializeFields(BeanSerializerBase.java:518)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize
(BeanSerializer.java:117)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer
.serializeContents(IndexedListSerializer.java:94)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer
.serializeContents(IndexedListSerializer.java:21)
...
如果我应该提供更多堆栈跟踪,请告诉我。有什么提示吗?
每次你有@OneToMany
(一个集合)你需要向它添加@JsonIgnore
否则它会导致无限循环导致堆栈溢出异常,因为它一直在之间查找parent(一侧)和 child(多侧)
有关处理此类问题的更多信息,请查看这篇优秀文章 http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
我尝试了在网上找到的所有方法,但都没有用。 None 任何注释。
但是在与这个问题进行了激烈的斗争之后,我找到了解决方案。
首先,您需要向两个实体(不是关系实体)添加此注释:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "relationClass"})
public class YourClass { ...
}
其中 "relationClass" 是关系的 class 的 List/Set 的名称:
例如:
@OneToMany(mappedBy = "yourClass", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<RelationClass> relationClass;
还需要在注释中指定"hibernateLazyInitializer"、"handler",否则会导致序列化问题。
之后,如果您看到定义关系 table 的 table,您将在其中看到行,并且在您的 JSON 响应中将不再是任何循环。所以我认为最好的解决方案也是为关系 tablee 创建一个存储库并从那里访问数据。
希望对大家有所帮助!
我觉得之前回答的问题是注解的封装问题。在文章中http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
@JsonManagedReference 和@JsonBackReference 工作正常。
但包裹应该是 com.fasterxml.jackson.annotation .
有时可能导入了其他包也无法解决问题。
另外添加
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
在模型的 class 定义工作正常之前。
public class A {
private String name;
@JsonIgnoreProperties(value = "linkToA") // remove field to avoid loop
private B linkToB;
}
public class B {
private String name;
@JsonIgnoreProperties(value = "linkToB") // remove field to avoid loop
private A linkToA;
}
您还可以使用 lombok 的 EqualsAndHashcode 注释,如下所示。
@EqualsAndHashcode(不包括 ={"following"})
public class 用户{}
我正在开发一个 EclipseLink 项目,其中一个用户可以 "follow" 另一个用户,就像在社交媒体网站上一样。我设置了一个 User
实体(引用一个名为 users
的 table),它有一个列表 "followers"(关注该用户的用户)和另一个列表 "following"(用户关注的用户)。该关系在名为 followers
的单独 table 中定义,其中包含关注用户 ID (user_id
) 和关注用户 ID (follower_id
) 的列。
我的用户模型如下所示:
@Entity
@Table(name = "users")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM USER u")
public class User {
// other attributes
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "follower", joinColumns = @JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "follower_id", referencedColumnName = "id"))
private List<User> followers;
@ManyToMany(mappedBy = "followers")
private List<User> following;
// other getters and setters
public List<User> getFollowers() {
return this.followers;
}
public List<User> getFollowing() {
return this.following;
}
}
getFollowers()
方法似乎工作正常,但是当调用 getFollowing()
时,我收到一堆控制台垃圾邮件,最终导致 WhosebugException:
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion
(WhosebugError) (through reference chain:
org.eclipse.persistence.indirection.IndirectList[0]-
>org.myproject.model.User["followers"]-
>org.eclipse.persistence.indirection.IndirectList[0]-
>org.myproject.model.User["following"]-
...
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase
.serializeFields(BeanSerializerBase.java:518)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize
(BeanSerializer.java:117)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer
.serializeContents(IndexedListSerializer.java:94)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer
.serializeContents(IndexedListSerializer.java:21)
...
如果我应该提供更多堆栈跟踪,请告诉我。有什么提示吗?
每次你有@OneToMany
(一个集合)你需要向它添加@JsonIgnore
否则它会导致无限循环导致堆栈溢出异常,因为它一直在之间查找parent(一侧)和 child(多侧)
有关处理此类问题的更多信息,请查看这篇优秀文章 http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
我尝试了在网上找到的所有方法,但都没有用。 None 任何注释。 但是在与这个问题进行了激烈的斗争之后,我找到了解决方案。
首先,您需要向两个实体(不是关系实体)添加此注释:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "relationClass"})
public class YourClass { ...
}
其中 "relationClass" 是关系的 class 的 List/Set 的名称:
例如:
@OneToMany(mappedBy = "yourClass", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<RelationClass> relationClass;
还需要在注释中指定"hibernateLazyInitializer"、"handler",否则会导致序列化问题。
之后,如果您看到定义关系 table 的 table,您将在其中看到行,并且在您的 JSON 响应中将不再是任何循环。所以我认为最好的解决方案也是为关系 tablee 创建一个存储库并从那里访问数据。
希望对大家有所帮助!
我觉得之前回答的问题是注解的封装问题。在文章中http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion @JsonManagedReference 和@JsonBackReference 工作正常。
但包裹应该是 com.fasterxml.jackson.annotation .
有时可能导入了其他包也无法解决问题。
另外添加
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
在模型的 class 定义工作正常之前。
public class A {
private String name;
@JsonIgnoreProperties(value = "linkToA") // remove field to avoid loop
private B linkToB;
}
public class B {
private String name;
@JsonIgnoreProperties(value = "linkToB") // remove field to avoid loop
private A linkToA;
}
您还可以使用 lombok 的 EqualsAndHashcode 注释,如下所示。
@EqualsAndHashcode(不包括 ={"following"}) public class 用户{}