无法编写JSON:无限递归(StackOverflowError);嵌套异常弹簧启动

时间:2017-12-07 10:37:42

标签: json spring hibernate spring-boot recursion

这是我的区域控制器,当我尝试保存后获取数据我得到错误,即使我尝试获取对象形式getDistrict(长ID)同样的罢工请建议一些方式,我是非常新的春天环境

    package com.gad.services;

    import java.util.List;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import com.gad.repositories.DistrictMasterRepositories;
    import com.gad.rmodels.Districtmaster;
    import com.gad.rmodels.Statemaster;

    @Service
    public class DistricMasterServices {

        @Autowired
        DistrictMasterRepositories districtMasterRepositories;
        @Autowired
        StateMasterServices stateMasterServices;
        List<Districtmaster> districtmaster;

        public Iterable<Districtmaster> savenewdistrict(Long id,Districtmaster districtmaster_rec){
             System.out.println(id);
             Statemaster statemaster=null;
             statemaster = stateMasterServices.getStateById(id);
             System.out.println("savenewdistrict");



                districtmaster_rec.setStatemaster(statemaster);
                districtMasterRepositories.save(districtmaster_rec);
                    Iterable<Districtmaster>districtmaster2 = districtMasterRepositories.findAll();
                    return  districtmaster2;


        }


        public Districtmaster  getDistrict(Long id){
            Districtmaster districtmaster =  districtMasterRepositories.findOne(id);
            return districtmaster;

        }
    }

州的模型类

 package com.gad.rmodels;
    import static javax.persistence.GenerationType.SEQUENCE;
    import java.util.HashSet;
    import java.util.Set;
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.SequenceGenerator;
    import javax.persistence.Table;

    /**
     * Statemaster generated by hbm2java
     */
    @Entity
    @Table(name="statemaster"
        ,schema="aop_gad_v1"
    )
    public class Statemaster  implements java.io.Serializable {


         private long id;
         private String stateName;
         private Set<Districtmaster> districtmasters = new HashSet<Districtmaster>(0);

        public Statemaster() {
        }


        public Statemaster(long id) {
            this.id = id;
        }
        public Statemaster(long id, String stateName, Set<Districtmaster> districtmasters) {
           this.id = id;
           this.stateName = stateName;
           this.districtmasters = districtmasters;
        }



        @SequenceGenerator(name="generator_statemasterid", sequenceName="aop_gad_v1.gad_statemaster_seq")
        @Id 
        @GeneratedValue(strategy=SEQUENCE, generator="generator_statemasterid")
        @Column(name="id", unique=true, nullable=false)
        public long getId() {
            return this.id;
        }

        public void setId(long id) {
            this.id = id;
        }

        @Column(name="state_name", length=20)
        public String getStateName() {
            return this.stateName;
        }

        public void setStateName(String stateName) {
            this.stateName = stateName;
        }

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
        public Set<Districtmaster> getDistrictmasters() {
            return this.districtmasters;
        }

        public void setDistrictmasters(Set<Districtmaster> districtmasters) {
            this.districtmasters = districtmasters;
        }




    }

分区模型

package com.gad.rmodels;


import static javax.persistence.GenerationType.SEQUENCE;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

/**
 * Districtmaster generated by hbm2java
 */
@SuppressWarnings("serial")
@Entity
@Table(name="districtmaster",schema="aop_gad_v1")
public class Districtmaster  implements java.io.Serializable {


     private long id;
     private Statemaster statemaster;
     private String districtName;
     private Set<GadGuestHouseMaster> gadGuestHouseMasters = new HashSet<GadGuestHouseMaster>(0);

    public Districtmaster() {
    }


    public Districtmaster(long id) {
        this.id = id;
    }
    public Districtmaster(long id, Statemaster statemaster, String districtName, Set<GadGuestHouseMaster> gadGuestHouseMasters) {
       this.id = id;
       this.statemaster = statemaster;
       this.districtName = districtName;
       this.gadGuestHouseMasters = gadGuestHouseMasters;
    }


     @SequenceGenerator(name="generator_districtmasterid", sequenceName="aop_gad_v1.gad_districtmasterid_seq")
     @Id 
     @GeneratedValue(strategy=SEQUENCE, generator="generator_districtmasterid")
     @Column(name="id", unique=true, nullable=false)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }
@ManyToOne(fetch=FetchType.LAZY)

    @JoinColumn(name="district_of_state")
    public Statemaster getStatemaster() {
        return this.statemaster;
    }

    public void setStatemaster(Statemaster statemaster) {
        this.statemaster = statemaster;
    }

    @Column(name="district_name", length=20)
    public String getDistrictName() {
        return this.districtName;
    }

    public void setDistrictName(String districtName) {
        this.districtName = districtName;
    }
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="districtmaster")
    public Set<GadGuestHouseMaster> getGadGuestHouseMasters() {
        return this.gadGuestHouseMasters;
    }

    public void setGadGuestHouseMasters(Set<GadGuestHouseMaster> gadGuestHouseMasters) {
        this.gadGuestHouseMasters = gadGuestHouseMasters;
    }




}

我得到的错误

  

[{&#34;时间戳&#34;:1512641978311,&#34;状态&#34;:200,&#34;错误&#34;:&#34; OK&#34;&#34;例外& #34;:&#34; org.springframework.http.converter.HttpMessageNotWritableException&#34;&#34;消息&#34;:&#34;莫非   不写JSON:无限递归(StackOverflowError);嵌套   异常是com.fasterxml.jackson.databind.JsonMappingException:   无限递归(StackOverflowError)(通过引用链:   com.gad.rmodels.Statemaster [\&#34; districtmasters \&#34;] - &GT; org.hibernate.collection.internal.PersistentSet [0] -

9 个答案:

答案 0 :(得分:13)

您正面临此问题,因为Statemaster模型包含区域主模型的对象,该模型本身包含Statemaster模型的对象。这会导致无限的json递归。

您可以通过3种方法解决此问题。

1 - 创建DTO并仅包含您要在响应中显示的字段。

2 - 您可以使用@JsonManagedReference@JsonBackReference注释。

E.g。将@JsonManagedReference注释添加到Statemaster模型。

@JsonManagedReference
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
public Set<Districtmaster> getDistrictmasters() {
    return this.districtmasters;
}

@JsonBackReference注释添加到区域主管模型。

@JsonBackReference
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="district_of_state")
public Statemaster getStatemaster() {
    return this.statemaster;
}

3 - 您可以在getter或setter方法上使用@JsonIgnore注释。

@JsonIgnore
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
public Set<Districtmaster> getDistrictmasters() {
    return this.districtmasters;
}

但是,这种方法会从响应中省略一组区域主管。

答案 1 :(得分:1)

那是因为对于json中的StatemasterDistrictmaster&#39}被放置。 每个Districtmaster本身都有Statemaster,所以它也会放入json中。这样你就可以获得无限递归

    @JsonIgnore
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, 
    mappedBy="statemaster")
    public Set<Districtmaster> getDistrictmasters() {
        return this.districtmasters;
    }

@JsonIgnore上添加Set<Districtmaster>注释将阻止该递归。 您可以将@JsonIgnore置于public Statemaster getStatemaster()

答案 2 :(得分:1)

Statemaster类中,将districtmasters设为List<Districtmaster>而不是Set<Districtmaster>,并相应地更改getter方法:public List<Districtmaster> getDistrictmasters()。 不幸的是,我无法解释为什么,但这对我有用。

答案 3 :(得分:1)

@JsonBackReference @JsonManagedReference 对我不起作用,因为我使用的是代表联接表的类,而使它起作用的唯一方法是将 @JsonBackReference 放在表示链接的类的字段上方。最终结果是,如果我使用JSON从连接类中提取一条记录,则不会显示任何连接字段,从而使返回的信息无用。

我会举一些例子,但我希望避免冗长的答复。以下文章中解释的 @JsonIdentityInfo 提供了一个简短,简单但高效的解决方案。

Solution Preview

Bidirectional relationships and InfiniteRecursion

答案 4 :(得分:1)

使用列表而不是集合。这就是我解决问题的方法。

答案 5 :(得分:0)

看起来你的问题是休眠关系。当您尝试序列化实体Statemaster时,序列化程序会调用Districtmaster集的序列化。反过来又以某种方式再次引用了国家大师。

有两种可能的解决方法 1. Unproxy对象

  1. 创建DTO(数据传输对象) - 您的实体的副本,其中应分配所有必填字段并返回DTO。

答案 6 :(得分:0)

在处理双向映射时会发生此问题。在DAO /实体类中使用@JsonManagedReferenc@JsonBackReference

@JsonManagedReference 是引用的前一部分-通常被序列化的引用。 @JsonBackReference 是参考的后半部分–序列化将忽略它。

(Read More)

答案 7 :(得分:0)

几天来我一直在同一个问题上挣扎,我尝试了@ JsonIgnore,@ JsonManagedReference和@JsonBackReference注释,甚至@JsonIdentityInfo注释,但它们都没有起作用。

如果您(将来的读者)处在相同的情况下,该解决方案将比您预期的要容易,只需将@JsonIgnore或@JsonManagedReference / @JsonBackReference 放在属性的getter上,而不是放在属性上本身。这样就可以了。

这是一个简单的示例:

假设我们有两个类,即Order和Product,以及它们之间的OneToMany关系。

订单类

public class Order{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private String id_order;
  private double price;
  @OneToMany(mappedBy = "order")
  @LazyCollection(LazyCollectionOption.FALSE)
  private List<Product> products
  //constructor, getters & setter 
}

产品类别:

public class Product{
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private String id_product;
   private String name;
   @ManyToOne
   @JoinColumn(name = "id_order")
   private Order order;
   //consturctor, getters & setters
 }

因此,为了使用@JsonManagedReference和@JsonBackReference,只需将它们添加到getter中,如下所示:

public class Order{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private String id_order;
  private double price;
  @OneToMany(mappedBy = "order")
  @LazyCollection(LazyCollectionOption.FALSE)
  private List<Product> products
  //constructor, getters & setter 
  @JsonManagedReference
  public List<Product> getProducts(){
    return products;
}

产品类别:

public class Product{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private String id_product;
  private String name;
  @ManyToOne
  @JoinColumn(name = "id_order")
  private Order order;
  //consturctor, getters & setters
  @JsonBackReference
  public Order getOrder(){
    return order;
  }
 }

答案 8 :(得分:0)

解决问题有两种不同的方法:


  1. 您需要implement Serializable对正在使用的所有 @Data 类/DTO,并确保生成一个 private static final long serialVersionUID为班级。 优点:您可以通过这种方式使用“lombok”@Data/@Getter/@Setter 注释。

  1. @JsonIgnore 放在所有正在使用的类/DTO 中的每个 getter/setter 上。 缺点:使用“lombok”@Data/@Getter/@Setter 注释可能会有问题。