我试图创建同一实体类型的父子关系。我面临的一个问题是,当尝试执行GET请求以检索子级不为空的实体时,我将从看起来像无限循环的地方获得堆栈溢出错误。环顾四周后,我发现了一个修复方法,只需在实体类的父字段中添加一个@JsonIgnore。我的问题是为什么这能解决这个问题?一开始是什么问题?
@Entity
@Table(name = "trash")
public class Trash {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String username;
@NotBlank
private String message;
private Long likes;
@ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JsonIgnore
private Trash parent;
@OneToMany(cascade = CascadeType.ALL, mappedBy="parent", orphanRemoval=true, fetch = FetchType.LAZY)
private Collection<Trash> children;
这是我收到的错误
2019-07-19 10:29:55.867 ERROR 14156 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is 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: com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"]-
repeats for awhile....
>com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash$HibernateProxy$lBPNIlf1["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.litter.model.Trash["parent"])] with root cause
java.lang.StackOverflowError: null
最佳答案
例外情况说明:
无法写入JSON:无限递归(StackOverflowError);嵌套异常为com.fasterxml.jackson.databind.JsonMappingException:无限递归(StackOverflowError)
(通过参考链:
>com.example.little.model.Trash[“父级”]-
>com.example.little.model.Trash$HibernateProxy$lBPNIlf1[“子项”]-
>org.hibernate.collection.internal.PersistentBag[0]>com.example.little.model.Trash[“父级”]-
>com.example.little.model.Trash$HibernateProxy$lBPNIlf1[“子项”]-
>org.hibernate.collection.internal.PersistentBag[0]-
>com.example.little.model.Trash[“父级”]-
>com.example.little.model.Trash$HibernateProxy$lBPNIlf1[“子项”]-
>org.hibernate.collection.internal.PersistentBag[0]-
>com.example.little.model.Trash[“父级”]-
所以为了。。。
字段序列化触发自身的字段序列化
触发parent
字段序列化,以便。。。
这看起来很抽象,下面是一个具体的例子。
假设这三个children
实例:一个父对象有两个子对象。
垃圾桶-1(儿童=2,3)
垃圾箱-2(父级:1)
垃圾箱-3(父级:1)
假设您想要序列化parent
(父项)。
以下是杰克逊的进展:
1)Jackson试图序列化Trash
字段,我们感兴趣的Trash-1
字段(Trash-1
和children
)。
所以它启动了Trash-2
序列化。
2)但是要序列化Trash-3
,Jackson还需要序列化它的字段,即children
字段!
3)我们回到第一步。
它一直持续到递归太重要而Jackson阻止了你。
通过用Trash-2
注释parent
或Trash-1
,您要求Jackson跳过两个序列化中的一个,从而中断递归。
例如,在parent
上,它将给出:
1)Jackson试图序列化children
字段,我们感兴趣的@JsonIgnore
字段(parent
和Trash-1
)。
所以它启动了children
序列化。
2)Trash-2
被序列化(不需要字段序列化)。
2)Trash-3
被序列化(不需要字段序列化)。
一切都结束了。