我正在使用基于 Spring Boot 和 Spring Data JPA 的 CRUD 存储库构建 REST API。
我对 JSON 序列化有疑问。许多实体都包含关系,我想在使用 get
方法检索数据时限制嵌套实体的数量。
这是按预期工作的两个实体的示例:
@Entity
@Table
public class Series {
private @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer id;
@Column(name = "publisher_id")
private @NotEmpty @NotNull Integer publisherId;
@Column(name = "title")
private @NotEmpty @NotNull String title;
@JsonManagedReference
@OneToMany(mappedBy = "series")
private List<Subseries> subseriesList;
public void addSubseries(Subseries subseries) {
subseriesList.add(subseries);
subseries.setSeries(this);
}
}
@Entity
@Table(name = "subseries")
public class Subseries {
private @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer id;
@Column(name = "series_id", insertable = false, updatable = false)
private @NotEmpty @NotNull Integer seriesId;
@Column(name = "title")
private @NotEmpty @NotNull String title;
@JsonBackReference
@ManyToOne
@JoinColumn(name = "series_id", foreignKey = @ForeignKey(name = "id"))
private @NotEmpty @NotNull Series series;
}
这两个类都实现了 Serializable
接口(interface),并具有它们的 getter 和 setter 以及空的构造函数。
这是 series/10
的 get
方法的输出:
{
"id": 10,
"publisherId": 100,
"title": "Title of the series",
"subseriesList": [
{
"id": 11,
"seriesId": 10,
"title": "Title of the first subseries"
},
{
"id": 12,
"seriesId": 10,
"title": "Title of the second subseries"
}
]
}
这是 subseries/11
的输出:
{
"id": 11,
"seriesId": 10,
"title": "Title of the first subseries"
}
到目前为止,一切都按预期工作:我需要所选系列的子系列,这就是我得到的。这个引用 Series
的实体出现了问题:
@Entity
@Table(name = "publication")
@NoArgsConstructor
public class Publication {
private @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer id;
@Column(name = "publisher_id")
private Integer publisherId;
@Column(name = "series_id", insertable = false, updatable = false)
private Integer seriesId;
@Column(name = "subseries_id")
private Integer subseriesId;
@Column(name = "cover_title")
private @NotEmpty @NotNull String coverTitle;
@JsonManagedReference
@ManyToOne
@JoinColumn(name = "series_id", foreignKey = @ForeignKey(name = "id"))
private Series series;
// TODO: @ManyToOne reference for Subseries
}
这个实体代表一本书,它可能属于一个系列,也可能属于该系列的子系列。我想获取引用的系列和子系列作为嵌套数据,但我不想获取系列的嵌套数据。这是我得到的:
{
"id": 56,
"publisherId": 100,
"seriesId": 10,
"subseriesId": 11,
"coverTitle": "Book title",
"series": {
"id": 10,
"publisherId": 100,
"title": "Title of the series",
"subseriesList": [
{
"id": 11,
"seriesId": 10,
"title": "Title of the first subseries"
},
{
"id": 12,
"seriesId": 10,
"title": "Title of the second subseries"
}
]
}
}
我不需要子系列的完整列表(另外,第二个与所选出版物无关)而且我不知道如何在出版物中删除它们而保留它们作为系列.这就是我想要的:
{
"id": 56,
"publisherId": 100,
"seriesId": 10,
"subseriesId": 11,
"coverTitle": "Book title",
"series": {
"id": 10,
"publisherId": 100,
"title": "Title of the series"
}
}
这只是一个例子,但我的项目中的许多其他实体也有同样的问题。
我有类似的问题here但情况有所不同,因为它适用于主要实体而不是嵌套实体。
有人建议我为 REST 服务使用单独的 POJO,但这会使代码难以维护。
我正在寻找的是像 @JsonIgnore
或 @JsonManagedReference
/@JsonBackReference
这样的东西,它允许在 Series
是主要实体,当它是嵌套实体时丢弃引用。另一种可能的解决方案是将嵌套实体的数量限制为一个。
有什么办法吗?
最佳答案
我认为您不能使用 JsonIgnore 来做到这一点。它是类级别的注释,不关心它是否被引用。它还用于向后序列化——所以如果 JSON 出现,它应该填充你的类,然后你会希望该字段不被忽略。所以它只是递归地传递给 children 。 您可以使用 @JsonFilter 并在属性运行时应用过滤器。这是一个例子:
https://www.tutorialspoint.com/jackson_annotations/jackson_annotations_jsonfilter.htm
但是为什么您首先需要它呢?
我会说 - 添加另一层对象(如您所说的 POJO)或者我们也可以称它们为 DTO ;)
https://stackabuse.com/data-transfer-object-pattern-in-java-implementation-and-mapping/
乍一看,这对于可维护性来说似乎更难,但我敢打赌,随着时间的推移,它会得到返回。序列化实体会导致很多麻烦,就像您遇到的那样。更糟糕的是当你得到循环依赖然后它变得不可序列化。另一个问题是数据泄露。我知道您可以使用 @JsonIgnore 隐藏一些属性,仅此而已。随着项目的增长,您可能会得出这样的结论:序列化实体并不能为您提供所需的灵 active 。最后但同样重要的是,您可以更好地定义类职责 - 实体代表系统中的状态,DTO 是您发送的内容。
关于java - 如何仅在引用实体时忽略 JSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64989194/