嵌套对象的无限递归Spring REST

时间:2015-11-05 09:03:07

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

我想知道如何使用具有双向关系的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;
    }
}

因此,从我观察到的情况来看,我可以在C类的反向引用中忽略C类中的杰克逊注释而不会对行为进行任何改变。这是已知行为还是我错过了什么?

更新1

我试图通过修改B类并删除C上的后向引用来消除B和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的存储库(Hooray!)上的GET请求的无限递归,但它也消除了在向A的存储库发送POST时存储C对象的可能性(boooh!)。这将抛出此错误消息:

  

org.hibernate.TransientObjectException:object引用未保存的瞬态实例 - 在刷新之前保存瞬态实例

更新2

我尝试为B类添加一个存储库。这导致了另一个无限递归。但这次应用程序和IDE崩溃,因为错误处理不当。

1 个答案:

答案 0 :(得分:0)

因此,如果我将Object B定义为存储库并使用

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

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

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

关于春假的有趣事实

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

的类的存储库
public class ACos

将无法正常运行且名为

的变量
private String aCos;

将被序列化为

  

{&#34; ACOS&#34;:&#34;无论&#34;}