java - 如何仅在引用实体时忽略 JSON?

标签 java json jpa spring-data-jpa

我正在使用基于 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/10get 方法的输出:

{
    "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/

相关文章:

java - 显示 Intellij 编译警告

java - 保存到对象的多个组合索引位置处的 1 个数组的条件

java - java中使用哪种数据类型?

java - 使用 spring DataAccessExceptions 代替 JPA PersistenceExceptions 有什么优势吗?

java - 我应该如何使用 Hibernate(JPA) 和 Gradle 构建我的 Java 代码?

java - 将对象编码为 CSV

json - 如何在 Perl 中合并两个复杂的数据结构?

jquery - AJAX Post 到 ASP.NET core MVC 6 Controller 操作方法和参数为 null

javascript - 获取 JSON 数组的长度

java - 父级未检索子级的 hibernate JPA