Spring 一对多关系中带弹簧靴的无限循环

Spring 一对多关系中带弹簧靴的无限循环,spring,spring-boot,spring-restcontroller,Spring,Spring Boot,Spring Restcontroller,在rest应用程序中,我使用SpringBoot和jpa 我有一个班级寄宿生 谁有 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger") private List<Reference> referenceList; 当我调用这个方法时 @RequestMapping(value = "/lodgers/{lodgerId}", method = RequestMethod

在rest应用程序中,我使用SpringBoot和jpa

我有一个班级寄宿生

谁有

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;
当我调用这个方法时

@RequestMapping(value = "/lodgers/{lodgerId}", method = RequestMethod.GET)
public Lodger getLogderById(@PathVariable("lodgerId") long lodgerId) {
    return lodgerService.getLodger(lodgerId);
}
我得到这个错误

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]->org.hibernate.collection.internal.PersistentBag[0]->server.bean.Reference["lodger"]->server.bean.Lodger["referenceList"]...

当您在返回对象中有一个循环,并且spring试图将其序列化为其他类型时,就会发生这种情况


尝试从返回的模型中创建不带周期的DTO或值对象(简单POJO),然后返回它。

不要通过REST webservice返回具有循环依赖关系的实体-创建新的DTO类,映射从数据库中获取的实体,并在webservice中返回它

更多信息请点击此处:


当然,如果您愿意,您可以使用另一个映射库,我个人最喜欢的是Orika()

让我们假设您的代码如下所示:-

Lodger.class

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
private List<Reference> referenceList;

public List<Reference> getReferenceList() {
    return referenceList;
}

public void setReferenceList(List<Reference> referenceList) {
    this.referenceList = referenceList;
}

@Override
public String toString() {
    return "Lodger[referenceList=" + referenceList + "]";
}
当您注意到在两个POJO中都编写了toString()方法时,您将看到我们正在从任意一方调用两个类的toString(),这导致从任意一方调用toString()方法的次数都是无限的,并且永远不会终止。为了避免这种情况,请从reference.class的toString()中删除任何引用[您也可以从Lodger类中删除。]因此,reference类的toString()中不会包含Lodger属性

最后,您的参考类将如下所示:-

参考类

@ManyToOne
@JoinColumn(name = "lodgerId")
private Lodger lodger;

public Lodger getLodger() {
    return lodger;
}

public void setLodger(Lodger lodger) {
    this.lodger = lodger;
}

@Override
public String toString() {
    return "Reference[lodger=" + lodger + "]";
}
@ManyToOne
@JoinColumn(name = "lodgerId")
private Lodger lodger;

public Lodger getLodger() {
    return lodger;
}

public void setLodger(Lodger lodger) {
    this.lodger = lodger;
}

@Override
public String toString() {
    return "Reference[Properties other than lodger=" + properties other than lodger + "]";
}
解决方案:

使用

@JsonManagedReference
第一个实例化对象的注释

@JsonBackReference
第二个实例化对象的注释

第一:

@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "lodger")
    private List<Reference> referenceList;

如果两个表中的主键名称相同,例如:id

加上这个

@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
    ...
}
和参考类

@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Reference {
    ...
}
有关参考,请参阅


您唯一需要的是,在您拥有注释的类中,使用希望在值部分跳过的属性实现下一个注释
@JsonIgnoreProperties(值={“yourtattribute”、“handler”、“hibernateLazyInitializer”},allowSetters=true)

我为您的代码举了一个例子->

@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties(value = {"referenceList", "handler","hibernateLazyInitializer"}, allowSetters = true)
@JoinColumn(name = "lodgerId")
private Lodger lodger;

您在
@JsonIgnoreProperties
上的值部分中放置的所有属性都将被忽略,有了它,您可以解决无限循环,并在将来将其用于具有相同格式的其他开发。

您将在此处找到最佳解决方案。如果您尚未获得解决方案,请发表意见。但这不会从第二个对象中给我lodgerId。此解决方案解决了主要问题,但产生了另一个问题问题是,现在我们根本没有得到第二个被引用的对象。你能在示例中解释更多关于这个的信息吗!
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Reference {
    ...
}
@JsonIgnoreProperties({"hibernateLazyInitializer","referenceList"}) at class Level
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties(value = {"referenceList", "handler","hibernateLazyInitializer"}, allowSetters = true)
@JoinColumn(name = "lodgerId")
private Lodger lodger;