Spring MVC - JSON无限递归

时间:2012-01-27 18:07:28

标签: json spring-mvc

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

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注释,我在尝试检索Person记录时也会收到无限递归错误。我在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注释的方式有问题,请告诉我。感谢

10 个答案:

答案 0 :(得分:40)

我之前遇到过这种情况。但是在将@JsonIgnore从私有字段移动到字段的getter 之后,无限递归就消失了。所以我的猜测是,@ JsonIgnore可能无法在私人领域工作。但是,javadoc或Jackson Java JSON处理器的教程没有提到这一点,所以我不能100%肯定。仅供参考。

答案 1 :(得分:10)

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

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

在我的情况下,我有两个相关的对象,如产品&lt; - &gt; ProductImage。所以JSON解析器进入一个无限循环,在下面输出@JsonIgnore注释来获取方法

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

在ProductImage和

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

在产品中。

通过注释,事情正常。

答案 2 :(得分:5)

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

答案 3 :(得分:2)

显然,自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;
  }

基本上,杰克逊使用编组过程将Set<PeopleOrg> organization(参考a的前向部分)转换为类似json的格式,然后查找引用的后半部分Person person并且不将其序列化

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

答案 4 :(得分:1)

如果A有B&amp; B有A.

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

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

class A
{    
B b;    
}

class B
{    
@JsonIgnore
A a;
}

这也适用于其中一对多的关系。

答案 5 :(得分:0)

这可能有点旧,但你可以在类级添加@JsonIgnore,它应该忽略所有属性。 e.g

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

答案 6 :(得分:0)

有时成员字段可能内部引用自身的同一类类型,这可能会导致toJson时出现无限递归

例如:您有一个成员字段Klass a,而该Klass的类定义如下所示。

class Klass {
    Klass mySibling;

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

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

答案 7 :(得分:0)

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

保留两个构造函数,首先是零构造,第二个构造函数是字段,两者都应该包含超级

答案 8 :(得分:0)

对我来说,我尝试了@ JsonIgnore,@ JsonManagedReference / @ JsonBackReference,但没有任何效果,直到我阅读了此Exception thrown ["hibernateLazyInitializer"] solution 1和此Exception thrown ["hibernateLazyInitializer"] solution 2

解决方案1将从fetch.LAZY更改为fetch.EAGER,解决方案2使用@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}),当然在两个解决方案中都使用@JsonIgnore

答案 9 :(得分:-2)

杰克逊通过打电话给吸气者来研究反思。我也遇到过这样一种情况:我在类中有一个相同Object的getter。杰克逊通过反复称自己的吸气剂进入无限递归吃掉筹码。删除了吸气剂,然后它被修复了。

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