JPA休眠一对一映射的堆栈溢出错误

JPA休眠一对一映射的堆栈溢出错误

本文介绍了Spring Data JPA休眠一对一映射的堆栈溢出错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题类似于这个 https://discourse.hibernate.org/t/hibernate-throws-org-hibernate-id-identifiergenerationexception-attempted-to-assign-id-从空到一对属性/1777 但是在应用此线程的答案后,我得到了另一个异常.

My problem is similar to this one https://discourse.hibernate.org/t/hibernate-throws-org-hibernate-id-identifiergenerationexception-attempted-to-assign-id-from-null-one-to-one-property/1777but I am getting a different exception after applying the answer from this thread.

我的实体:

@Entity
@Table(name = "location")
public class Location {

    @Id
    private Long id;

    @Column(name = "country_code")
    private String countryCode;

    private Double longitude;

    private Double latitude;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private Distributor distributor;

    public Distributor getDistributor() {
        return distributor;
    }

// here I apply the advice from the linked thread above
    public void setDistributor(Distributor distributor) {
        this.distributor = distributor;
        this.id = distributor.getId();
    }
// other getters/setters
}
@Entity
@Table
public class Distributor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String site;

    @OneToOne(
            mappedBy = "distributor",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY,
            optional = false
    )
    private Location location;

// getters/setters/constructor

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Distributor )) return false;
        Distributor that = (Distributor ) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

}

具有相应的Spring数据存储库的控制器:

Controller with corresponding Spring Data Repository:

    @PostMapping
    public ResponseEntity<Distributor> test(@RequestBody Distributor distributor) {
        distributor.getLocation().setDistributor (distributor);

        return ResponseEntity.ok(repository.save(distributor));
    }

有了这个有效载荷:

{
    "name" : "name1",
    "location" : {
        "countryCode" : "US",
        "longitude" : 34 ,
        "latitude" : 12
    }
}

我收到了带有正确字段(分配器->位置->分配器->位置..)的无休止的嵌套响应,以SO错误结尾:

I am getting an endless nested response with proper fields(distributor -> location -> distributor -> location ..), which ends with SO Error:

java.lang.StackOverflowError: null
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[na:na]
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) ~[na:na]
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579) ~[na:na]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:741) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:723) ~[jackson-databind-2.11.0.jar:2.11.0]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166) ~[jackson-databind-2.11.0.jar:2.11.0]
....

我无法理解为什么会发生这种情况,我遵循了所有可用的教程.

I can't fathom why does this happen, I followed all available tutorials.

推荐答案

这是因为LocationDistributor之间存在循环依赖关系.

That's because there is a cyclic dependency between Location and Distributor.

由于两者相互引用,因此它们会继续序列化内部引用.

As both have reference to each other, they keep serializing inner reference.

您可以避免使用jackson注释@JsonBackReference@JsonManagedReference.

You can avoid that using jackson annotation @JsonBackReference and @JsonManagedReference.

JsonManagedReference:正向引用并序列化带注释的属性

JsonManagedReference : forward reference and serializes annotated property

在您的情况下,这应该可行.

In your case, this should work.

//Distributor class
@JsonManagedReference
private Location location;

//Location class
@JsonBackReference
private Distributor distributor;

这篇关于Spring Data JPA休眠一对一映射的堆栈溢出错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 20:27