无法写入 JSON:无限递归 (StackOverflowError);嵌套异常弹簧靴
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47693110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Could not write JSON: Infinite recursion (StackOverflowError); nested exception spring boot
提问by Bikash Dhal
This is my District Controller, when I try to fetch data after saving I get the error, even when I try get object form getDistrict(Long id)the same strikes please suggest some way, am very new at spring environment:
这是我的区域控制器,当我在保存后尝试获取数据时出现错误,即使我尝试从getDistrict(Long id)相同的罢工中获取对象,请提出一些建议,我在 spring 环境中非常新:
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;
}
}
The model class for state:
状态的模型类:
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;
}
}
Distric model:
地区模式:
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;
}
}
The Error I get:
我得到的错误:
[{"timestamp":1512641978311,"status":200,"error":"OK","exception":"org.springframework.http.converter.HttpMessageNotWritableException","message":"Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.Hymanson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.gad.rmodels.Statemaster[\"districtmasters\"]->org.hibernate.collection.internal.PersistentSet[0]-
[{"timestamp":1512641978311,"status":200,"error":"OK","exception":"org.springframework.http.converter.HttpMessageNotWritableException","message":"无法写入JSON:无限递归(StackOverflowError); 嵌套异常是 com.fasterxml.Hymanson.databind.JsonMappingException: Infinite recursion (StackOverflowError)(通过参考链:com.gad.rmodels.Statemaster[\"districtmasters\"]->org.hibernate.collection.internal .PersistentSet[0]-
回答by Shoeb Shaikh
You are facing this issue because the Statemaster model contains the object of Districtmaster model, which itself contains the object of Statemaster model. This causes an infinite json recursion.
您面临这个问题是因为 Statemaster 模型包含 Districtmaster 模型的对象,而 Districtmaster 模型本身包含 Statemaster 模型的对象。这会导致无限的 json 递归。
You can solve this issue by 3 methods.
您可以通过 3 种方法解决此问题。
1 - Create a DTO and include only the fields that you want to display in the response.
1 - 创建 DTO 并仅包含您要在响应中显示的字段。
2 - You can use the @JsonManagedReferenceand @JsonBackReferenceannotations.
2 - 您可以使用@JsonManagedReference和@JsonBackReference注释。
E.g. Add the @JsonManagedReferenceannotation to the Statemaster model.
例如,将@JsonManagedReference注释添加到 Statemaster 模型中。
@JsonManagedReference
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
public Set<Districtmaster> getDistrictmasters() {
return this.districtmasters;
}
Add the @JsonBackReferenceannotation to the Districtmaster model.
将@JsonBackReference注释添加到 Districtmaster 模型。
@JsonBackReference
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="district_of_state")
public Statemaster getStatemaster() {
return this.statemaster;
}
3 - You can use the @JsonIgnoreannotation on the getter or setter method.
3 - 您可以@JsonIgnore在 getter 或 setter 方法上使用注释。
@JsonIgnore
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
public Set<Districtmaster> getDistrictmasters() {
return this.districtmasters;
}
However, this approach will omit the set of Districtmaster from the response.
但是,这种方法会从响应中省略 Districtmaster 集。
回答by Faouzi
I've been struggling with the same problem for days, I tried @JsonIgnore, @JsonManagedReference and @JsonBackReference annotation, and even @JsonIdentityInfo annotation and none of them have worked.
几天来我一直在为同样的问题苦苦挣扎,我尝试了 @JsonIgnore、@JsonManagedReference 和 @JsonBackReference 注释,甚至是 @JsonIdentityInfo 注释,但都没有奏效。
If you (the future readers ) are in the same situation, the solution is easier than you expected, simply put @JsonIgnore or @JsonManagedReference / @JsonBackReference on the attribute's getterand not on the attribute itself. And that will do.
如果您(未来的读者)处于相同的情况,解决方案比您预期的要容易,只需将 @JsonIgnore 或 @JsonManagedReference / @JsonBackReference放在属性的 getter 上,而不是放在属性本身上。那就行了。
Here's a simple example how to do so :
这是一个简单的例子,如何做到这一点:
Say we have two classes, Order and Product, and OneToMany relation between them.
假设我们有两个类,Order 和 Product,以及它们之间的 OneToMany 关系。
Order class
订单类
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
}
Product Class:
产品类别:
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
}
So in order to use @JsonManagedReference and @JsonBackReference, just add them to the getters as the following :
因此,为了使用 @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;
}
Product class:
产品类别:
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;
}
}
回答by Serg Vasylchak
That's because for Statemasterin json the set of Districtmaster's is put.
And each Districtmasterhas the Statemasterin itself, so it's also put into the json. So that you get the infinite recursion
那是因为Statemaster在 json 中放置了Districtmaster's的集合。每个本身Districtmaster都有Statemaster,所以它也被放入了json。这样你就得到了无限递归
@JsonIgnore
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY,
mappedBy="statemaster")
public Set<Districtmaster> getDistrictmasters() {
return this.districtmasters;
}
Adding @JsonIgnoreannotation on Set<Districtmaster>will prevent that recursion.
You can put the @JsonIgnoreat public Statemaster getStatemaster()either.
添加@JsonIgnore注释Set<Districtmaster>将阻止这种递归。你可以把@JsonIgnore在public Statemaster getStatemaster()。
回答by StanislavL
Looks like your problem is Hibernate relations. When you try to serialize the entity Statemasterthe serializer calls serialization of the Districtmasterset which in turn somehow reference the Statemasteragain.
看起来您的问题是 Hibernate 关系。当您尝试序列化实体时Statemaster,序列化器会调用Districtmaster集合的序列化,而集合又以某种方式Statemaster再次引用。
There are two possible ways to solve:
有两种可能的解决方法:
- Unproxy object
- Create DTO (Data Transfer Object) - kind of copy of your entity where all necessary fields should be assigned and return the DTO.
- 取消代理对象
- 创建 DTO(数据传输对象) - 实体的一种副本,应在其中分配所有必需的字段并返回 DTO。
回答by Rishabh Agarwal
This issue occurs when dealing with bi-directional mapping. Use @JsonManagedReferencand @JsonBackReferencein DAO/Entity class
处理双向映射时会出现此问题。在 DAO/Entity 类中使用@JsonManagedReferenc和@JsonBackReference
@JsonManagedReferenceis the forward part of reference – the one that gets serialized normally. @JsonBackReferenceis the back part of reference – it will be omitted from serialization.
@JsonManagedReference是引用的前向部分——正常序列化的部分。 @JsonBackReference是引用的后面部分——它将从序列化中省略。
回答by Mario Varchmin
In the Statemasterclass make districtmastersa List<Districtmaster>instead of Set<Districtmaster>and change the getter method accordingly: public List<Districtmaster> getDistrictmasters().
Unfortunately I can not explain why, but this worked for me.
在Statemaster班级做districtmasters一个List<Districtmaster>代替Set<Districtmaster>,并相应地改变getter方法:public List<Districtmaster> getDistrictmasters()。不幸的是,我无法解释原因,但这对我有用。
回答by Joseph Waweru
@JsonBackReferenceand @JsonManagedReferencedidn't work for me since I was using a class that represented a join table and the only way to get it to work was to put the @JsonBackReferenceabove the fields representing the linked classes. The net effect was that if I was pulling a record from the join class using JSON, none of the join fields would show up, making the returned information useless.
@JsonBackReference和@JsonManagedReference对我不起作用,因为我使用的是代表连接表的类,而让它工作的唯一方法是将@JsonBackReference放在代表链接类的字段上方。最终效果是,如果我使用 JSON 从连接类中提取记录,则不会显示任何连接字段,从而使返回的信息无用。
I'd give examples but I like to avoid long replies. @JsonIdentityInfoexplained in the article below provides a short, simple but highly efficient solution.
我会举一些例子,但我喜欢避免冗长的回复。下面文章中解释的@JsonIdentityInfo提供了一个简短、简单但高效的解决方案。


