Spring MVC - JSON无限递归

问题描述 投票:0回答:12

我有这样的双向关系...

Person.java

 public class Person{

    @JsonIgnore
    @OneToMany(targetEntity=PersonOrganization.class, cascade=CascadeType.ALL,
        fetch=FetchType.EAGER, mappedBy="person")
    private Set<PeopleOrg> organization;
    .....
 }

PersonOrganization.java

  public class PersonOrganization{

    @JsonIgnore
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="PERSONID", nullable=false)
private Person person;
  }

即使使用

@JsonIgnore
注释,我在尝试检索人员记录时也会遇到无限递归错误。我在1.6版本中尝试过新的注释。
@JsonBackReference
@JsonManagedReference
。即使那样我也会得到无限递归..

@JsonBackReference("person-organization")
放在
Person
上并将
@JsonManagedReference("person-organization")
放在
PersonOrganization

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.entity.Person["organization"]->org.hibernate.collection.PersistentSet[0]->com.entity.PersonOrganization["person"]->com.entity.Person["organization"]->org.hibernate.collection.PersistentSet[0]...

即使我交换注释,我仍然遇到此异常。如果映射或我使用 JSON 注释的方式有问题,请告诉我。谢谢

json spring-mvc
12个回答
40
投票

我以前也遇到过这个问题。但是将 @JsonIgnore 从私有字段移动到字段的 getter 后,无限递归就消失了。所以我的疯狂猜测是 @JsonIgnore 可能在私有领域不起作用。然而,Jackson Java JSON-processor 的 javadoc 或教程没有提到这一点,所以我不能 100% 确定。仅供您参考。


10
投票

下面的链接说你应该注释JSON工具用来遍历对象图的方法,以指示它忽略遍历。

http://jackson.codehaus.org/1.0.1/javadoc/org/codehaus/jackson/annotate/JsonIgnore.html

就我而言,我有两个相关的对象,例如 Product <-> ProductImage。因此 JSON 解析器进入无限循环,而没有在以下内容上使用 @JsonIgnore 注释来获取方法

@JsonIgnore
public Product getImageOfProduct() {
    return imageOfProduct;
}

在产品图片中和

@JsonIgnore
public Set<ProductImage> getProductImages() {
    return productImages;
}

在产品中。

有了注释,一切正常。


5
投票

我知道这个问题并不是专门关于 Spring Data REST 的,但我在 Spring Data REST 的上下文中遇到了这个异常,并且想分享问题是什么。我有一个涉及没有存储库的实体的双向关系。创建存储库使循环消失。


4
投票

从 Jackson 1.6 开始,您可以使用两个注释来解决无限递归问题,而无需在序列化期间忽略 getter/setter:@JsonManagedReference 和 @JsonBackReference。

有关更多详细信息,请参阅https://stackoverflow.com/a/18288939/286588


3
投票

显然从 Jackson 1.6 开始,你可以使用 @JsonManagedReference@JsonBackReference 来有效解决无限递归问题。

我不会详细介绍,但是将您的课程更改为以下格式应该可以解决问题。

 public class Person{

    @OneToMany(targetEntity=PersonOrganization.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="person")
    @Column(nullable = true)
    @JsonManagedReference
    private Set<PeopleOrg> organization;
    .....
 }

public class PersonOrganization{

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="PERSONID")
    @JsonBackReference
    private Person person;
  }

基本上,Jackson 使用编组过程将引用 a 的前部部分

Set<PeopleOrg> organization
转换为类似 json 的格式,然后查找引用的后部部分
Person person
并且不对其进行序列化。

致谢 - Kurt Bourbaki 及更多信息 - http://keenformatics.blogspot.co.ke/2013/08/how-to-solve-json-infinite-recursion.html


1
投票

如果 A 有 B,B 有 A。

这是一对一的关系,但是形成了循环关系。

在任何类中,使用 JustIgnore 注释。

class A
{    
B b;    
}

class B
{    
@JsonIgnore
A a;
}

这也适用于其他关系,例如一对多。


0
投票

这可能有点旧,但您可以在类级别添加 @JsonIgnore 及其应忽略的所有属性。例如

@JsonIgnore("productImaes","...")
public class Product{ ...
}

0
投票

有时,成员字段可能具有对其自身相同类类型的内部引用,这可能会导致toJson时的

无限递归

例如:你有一个成员字段

Klass a
,而该Klass的类定义如下。

class Klass {
    Klass mySibling;

    public toString() {
        return "something" + mySibling.whateverMethod;
    }
}

解决方案:重构成员字段,消除内部引用。


0
投票

这个异常是因为,你的构造函数字段不正确,请再次检查你的类中的构造函数属性,并检查映射是否正确,

保留两个构造函数,第一个是零构造,第二个构造函数带有字段,并且都应该包含 super


0
投票

对我来说,我尝试过@JsonIgnore,@JsonManagedReference / @JsonBackReference,但没有任何效果,直到我读到此抛出异常[“hibernateLazyInitializer”]解决方案1和此抛出异常[“hibernateLazyInitializer”]解决方案2

解决方案1是从fetch.LAZY改为fetch.EAGER,解决方案2是使用

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
,当然这两个解决方案都使用@JsonIgnore


0
投票

就我而言,我导入了错误的 @JsonIgnore 注释,例如 net.minidev.json.annotate.JsonIgnore 而不是 com.fasterxml.jackson.annotation.JsonIgnore。更改此导入为我解决了无限递归问题。


-2
投票

Jackson 通过调用 getter 来处理 Reflection。我也遇到过这样的情况,我在其类中有一个相同对象的吸气剂。 Jackson 通过反复调用自己的 getter 来进入无限递归,吞噬堆栈。删除了 getter,然后就修复了。

我的建议: 如果你想使用 jackson 来转换对象,永远不要保留引用同一对象的 getter,就像单例的情况一样。

© www.soinside.com 2019 - 2024. All rights reserved.