【问题标题】:Serialize bi-directional JPA entities to JSON with jackson使用杰克逊将双向 JPA 实体序列化为 JSON
【发布时间】:2014-05-02 03:48:45
【问题描述】:

我正在使用 Jackson 将我的 JPA 模型序列化为 JSON。

我有以下课程:

import com.fasterxml.jackson.annotation.*;
import javax.persistence.*;
import java.util.Set;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
@Entity
public class Parent {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;

  @JsonManagedReference
  @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  private Set<Child> children;

  //Getters and setters
}

import com.fasterxml.jackson.annotation.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
@Entity
public class Child {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;

  @JsonBackReference
  @ManyToOne
  @JoinColumn(name = "parentId")
  private Parent parent;

  //Getters and setters
}

我正在使用 POJO 映射从模型序列化到 JSON。当我序列化父对象时,我得到以下 JSON:

{
  "id": 1,
  "name": "John Doe",
  "children": [
    {
      "id": 1,
      "name": "child1"
    },{
      "id": 2,
      "name": "child2"
    }
  ]
}

但是当我序列化一个 Child 时,我得到以下 JSON:

{
  "id": 1,
  "name": "child1"
}

缺少对父级的引用。 有没有办法解决这个问题?

【问题讨论】:

  • 在实体中包含与 UI 相关的逻辑(即 json 注释)不是很糟糕吗?这不是扼杀模块化吗?
  • 嗯...不。这就是实体存在的主要原因:作为数据模型表示,无论是 JPA、XML、JSON 还是这些的组合。让您的整个应用程序使用一组实体是设计良好的应用程序的指标 - 一组实体会导致单点故障,这反过来使应用程序在更高程度上可维护(和可交换)。跨度>

标签: java json hibernate jpa jackson


【解决方案1】:

我认为您必须在 @JsonIdentityInfo@JsonBackReference / @JsonManagedReference 之间进行选择。

我会在你的实体上使用:@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id"),删除 @JsonBackReference / @JsonManagedReference 对。

并在要排除的字段上添加@JsonIgnore

【讨论】:

    【解决方案2】:

    您可以使用 JsonManagedReference / JsonBackReference 同时使用 JsonIdentityInfo 来补充双向关系。

    有问题的班级:

    // bi-directional one-to-many association to Answer (Question is owner)
    @JsonManagedReference
    @OneToMany(mappedBy = "question", cascade = CascadeType.ALL)
    @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@QuestionAnswers")
    private Set<Answer> answers = new HashSet<>();
    

    在回答类中: // 与 Question 的双向多对一关联

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "questionId", referencedColumnName="id", foreignKey = @ForeignKey(name = "fk_answer_question"))
    private Question question;
    

    如果您需要子对象中的父引用,请删除托管/反向引用,这对我来说很好。

    【讨论】:

    • 什么是属性=“@QuestionAnswers”?据我了解,类的名称是 Answer 和 Question
    • 同时使用两者对我没有任何帮助。 @JsonManagedReference/BackReference 似乎覆盖了@JsonIdentityInfo。
    【解决方案3】:

    问题在于使用托管/反向引用要求遍历的方向始终是从父级到子级(即首先使用托管引用)。这是这些注释的限制。

    正如另一个答案所暗示的那样,使用对象 ID 是更灵活的替代方法,可能可行。

    另一个可能可行的选项是使用 JSON 视图或 JSON 过滤器来有条件地包含/排除父引用,如果您可以分开案例的话。这可能会变得一团糟。

    【讨论】:

      【解决方案4】:

      @JsonIgnoreProperties({"excludedPropertyName"}) 可以胜任。

      @Entity
      public class Parent {
      
          @JsonIgnoreProperties({"parent"})
          @OneToMany(mappedBy = "parent")
          private List<Child> children; 
      
          // ...
      }
      
      @Entity
      public class Child {
      
          @JsonIgnoreProperties({"children"})
          @ManyToOne
          private Parent parent;
      
          // ...
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用@JsonBackReference/@JsonManagedReference 并将此方法添加到孩子

        @JsonProperty
        public Long getParentId() {
            return parent == null ? null : parent.getId();
        }
        

        结果将是:

        {
          "id": 1,
          "name": "child1",
          "parentId": 1
        }
        

        我希望这对某人有所帮助。

        【讨论】:

        • 帮助获取 parentIds。但是当我尝试向系统添加新实体并在 json 中指定时,例如"parentId":3 这不会持久化到数据库。 parentId 结果为空。也许你知道为什么?
        猜你喜欢
        • 1970-01-01
        • 2015-04-07
        • 1970-01-01
        • 1970-01-01
        • 2012-01-26
        • 1970-01-01
        • 1970-01-01
        • 2016-10-28
        • 1970-01-01
        相关资源
        最近更新 更多