使用杰克逊将双向 JPA 实体序列化为 JSON
Posted
技术标签:
【中文标题】使用杰克逊将双向 JPA 实体序列化为 JSON【英文标题】:Serialize bi-directional JPA entities to JSON with jackson 【发布时间】: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 还是这些的组合。让您的整个应用程序使用一组实体是设计良好的应用程序的指标 - 一组实体会导致单点故障,这反过来使应用程序在更高程度上可维护(和可交换)。跨度> 【参考方案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 结果为空。也许你知道为什么?以上是关于使用杰克逊将双向 JPA 实体序列化为 JSON的主要内容,如果未能解决你的问题,请参考以下文章
是否有相当于杰克逊的@JsonAnyGetter/@JsonAnySetter 的 JPA 注释?
杰克逊 JSON、Spring MVC 4.2 和 Hibernate JPA 问题的无限递归