如何使用自引用处理实体的RESTful响应

时间:2017-03-15 13:39:14

标签: java json rest jpa jackson

我有一个Foo类,它引用了它自己。 这是我遇到的情况的一个粗略的例子。

@Entity
public class Foo() {
  @Column(name = "id", unique = true, nullable = false)
  private Long id;

  @JsonIgnore
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "id_Foo")
  private Foo parent;
}

当我将Foo对象传递给JSON响应生成器时,将启动所有必需的getter,并通过JPA从DB检索所有必需的数据。

现在的问题是,如果我从自引用字段中删除@JsonIgnore,我将获得父信息和父父信息等。

我想要的是我可以限制检索到的父信息。 例如。:

  • 深0 - 我只会获得Foo数据
  • 深度1 - 我将获得Foo和Foo父母的数据
  • Deep 2 - 我将获得Foo和Foo父和Foo父母的数据 等

也许有一个带注释或smth的简单解决方案,因为我找不到任何东西。

修改

使用自定义序列化程序和一些递归魔法解决了这个问题。

private void serializeParents(JsonGenerator gen, Foo value, int currentDepth) {
    if (currentDepth < PARENTS_DEPTH) {
      if (value.getMom() != null) {
        serializeParentData(gen, value.getMom(), currentDepth);
      }

      if (value.getDad() != null) {
        serializeParentData(gen, value.getDad(), currentDepth);
      }
    }
}

private void serializeParentData(JsonGenerator gen, Foo value, int currentDepth) {
    gen.writeObjectFieldStart(Gender.M.equals(value.getGender()) ? "dad" : "mom");
    // other parameters ...
    serializeParents(gen, value, currentDepth + 1);
    gen.writeEndObject();
}

1 个答案:

答案 0 :(得分:2)

我认为最好的方法是创建一个自定义DTO对象来收集所有Foo属性及其parent,这样您就不会获得递归关系并避免懒惰加载例外。

因此,您将保持您的实体不变:

@Entity
public class Foo() {
   @Column(name = "id", unique = true, nullable = false)
   private Long id;

   @JsonIgnore
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "id_Foo")
   private Foo parent;
}

并创建一个这样的自定义DTO对象:

public class FooDto() {

   private Long id;
   private Foo parent;

   //getters and setters here
}

然后您可以使用此DTO将JSOn结果存储在您的请求中。

您可以查看What is the point of using DTO (Data Transfer Objects)?了解更多详情。

@JsonIgnore文档:

根据杰克逊@JsonIgnore documentation,没有这样的选项(属性)来指定注释的深度/级别,因为只有一个可能的属性value来定义如果这种情况是否有效。