【问题标题】:Infinite recursion on nested objects Spring REST嵌套对象的无限递归 Spring REST
【发布时间】:2016-02-06 00:52:43
【问题描述】:

我想知道如何使用具有双向关系的 Spring REST 处理序列化。我目前正在使用 Spring Boot 1.3.0.BUILD-SNAPSHOT

目前我收到内部服务器错误,说明主类存储库上的 GET 请求无限递归。

它适用于两个类,其中一个是存储库。在示例中,A 是具有存储库的那个:

@Entity
public class A implements Serializable {
    private static final long serialVersionUID = 1L;

    @OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
    @JsonManagedReference
    private List<B> b;

    public A() {

    }
    public List<B> getB() {
        return b;
    }
    public void setCategory(List<B> b) {
        this.b = b;
        for (B oneB : this.category) {
            oneB.setA(this);
        }
    }
}

@Entity
public class B implements Serializable {
    private static final long serialVersionUID = 1L;

    @ManyToOne
    @JoinColumn(name = "b_column")
    @JsonBackReference
    @RestResource(rel = "BParent")
    private A a;

    public B() {

    }
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
}

但是,如果我在 B 中添加另一个类,它将不再起作用,并且如果我向 A 的存储库发送 GET 请求,我将获得无限递归(C 在其 b 属性上具有与 B 相同的注释) :

@Entity
public class B implements Serializable {
    private static final long serialVersionUID = 1L;

    @ManyToOne
    @JoinColumn(name = "b_column")
    @JsonBackReference
    @RestResource(rel = "BParent")
    private A a;

    @OneToMany(mappedBy = "c", cascade = CascadeType.ALL)
    @JsonManagedReference
    private List<C> c;

    public B() {

    }
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
}

因此,根据我的观察,我可以在对 B 的反向引用中省略 C 类中的 Jackson 注释,而不会改变行为。这是已知的行为还是我错过了什么?

更新 1

我试图通过修改B类来摆脱B和C对象之间的双向关系,并移除C上的反向引用:

@Entity
public class B implements Serializable {
    private static final long serialVersionUID = 1L;

    @ManyToOne
    @JoinColumn(name = "b_column")
    @JsonBackReference
    @RestResource(rel = "BParent")
    private A a;

    //This is now a unidirectional relationship to C
    @NotNull
    @OneToMany
    @JoinColumn(name="b_id", referencedColumnName="id")
    private List<C> c;

    public B() {

    }
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }

    public List<C> getC() {
    return c;
    }

    public void setC(List<C> c) {
       this.c= c;
    }
}

虽然这消除了 A 的存储库上的 GET 请求时的无限递归(万岁!),但它也消除了在向 A 的存储库发送 POST 时存储 C 对象的可能性(嘘!)。这将抛出此错误消息:

org.hibernate.TransientObjectException: 对象引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例

更新 2

我尝试为 B 类添加存储库。这导致了另一个无限递归。但是这一次应用程序和 IDE 只是因为错误没有得到正确处理而崩溃。

【问题讨论】:

    标签: spring-boot jackson spring-hateoas spring-rest


    【解决方案1】:

    如果我将对象 B 定义为存储库并用

    注释类 A 上的 a 属性,那么基本上什么样的工作方式
    @RestResource(exported = false)
    @OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
    @JsonManagedReference
    private List<B> b;
    

    如果以这种方式注释对象 C 将被正确序列化,而不会产生任何无限递归废话。

    如果有人有好的解释或解决方案,我会很乐意将其标记为答案。


    关于 Spring Rest 的趣事

    Spring Rest 对具有多个连续大写字母的变量/类名称存在一些问题。 例如,一个名为

    的类的存储库
    public class ACos
    

    将无法正常工作并命名为变量

    private String aCos;
    

    将被序列化为

    {"acos":"随便"}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多