【问题标题】:How to JSON ignore only when an entity is referenced?如何仅在引用实体时忽略 JSON?
【发布时间】:2021-03-07 09:28:17
【问题描述】:

我正在使用基于 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 接口,并有它们的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 是主要实体时允许保留引用并在它是嵌套实体时丢弃引用。另一种可能的解决方案是将嵌套实体的数量限制为一个。

有什么办法吗?

【问题讨论】:

    标签: java json jpa spring-data-jpa


    【解决方案1】:

    我认为你不能用 JsonIgnore 做到这一点。它是类级别的注释,不关心它是否被引用。它还用于向后序列化 - 所以如果 JSON 出现,它应该填充你的类,然后你会希望该字段不被忽略。所以它只是递归地传递给孩子们。 您可以使用 @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 隐藏一些属性,但仅此而已。随着项目的发展,您可能会得出这样的结论:序列化实体并不能提供您想要的灵活性。最后但并非最不重要的一点是,您有更好定义的类职责 - 实体代表系统中的状态,DTO 是您发送的内容。

    【讨论】:

      猜你喜欢
      • 2019-05-18
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多