【问题标题】:Spring MVC - JSON infinite recursionSpring MVC - JSON 无限递归
【发布时间】:2012-02-20 17:12:58
【问题描述】:

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

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。即使那样我也得到了无限递归..

Person 上使用@JsonBackReference("person-organization"),在PersonOrganization 上使用@JsonManagedReference("person-organization")

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


    【解决方案1】:

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

    【讨论】:

    • 我现在可以给你一个大大的吻。这解决了我的问题。就我而言,该字段受到保护。
    • 还不够,我还有问题。
    【解决方案2】:

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

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

    在我的例子中,我有两个相关的对象,比如这个产品 ProductImage。所以 JSON 解析器进入了一个无限循环,下面没有 @JsonIgnore 注释来获取方法

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

    在 ProductImage 和

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

    在产品中。

    有了注释,一切正常。

    【讨论】:

    • 注释 getter 而不是字段对我有用。是 8.5 JEE 6。
    【解决方案3】:

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

    【讨论】:

    • 我有两个存储库,但我仍然有循环
    • 我找到了解决方案:我们需要在 Projections 上使用 @JsonManagedReference 和 @JsonBackReference(不在实体中)
    【解决方案4】:

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

    更多详情请咨询https://stackoverflow.com/a/18288939/286588

    【讨论】:

      【解决方案5】:

      显然从 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&lt;PeopleOrg&gt; organization 转换为类 json 格式,然后查找引用的后半部分 Person person 并且不对其进行序列化。

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

      【讨论】:

        【解决方案6】:

        如果 A 有 B,B 有 A。

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

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

        class A
        {    
        B b;    
        }
        
        class B
        {    
        @JsonIgnore
        A a;
        }
        

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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

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

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

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

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

            【讨论】:

              【解决方案9】:

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

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

              【讨论】:

                【解决方案10】:

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

                方案一是从fetch.LAZY改成fetch.EAGER,方案二是使用@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}),当然两个方案都使用@JsonIgnore

                【讨论】:

                  【解决方案11】:

                  Jackson 通过调用 getter 来处理反射。我也遇到过这样的情况,我在它的类中有一个相同对象的吸气剂。杰克逊通过反复调用自己的吸气剂进入无限递归吃掉堆栈。移除了 getter,然后它得到了修复。

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

                  【讨论】:

                    猜你喜欢
                    • 2023-03-26
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-11-28
                    • 2019-07-19
                    • 2020-07-23
                    • 2020-05-13
                    • 2016-04-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多