java REST 控制器中具有一对多关系的实体的递归 JSON 视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31465440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 18:39:31  来源:igfitidea点击:

Recursive JSON view of an entity with one-to-many relationship in REST controller

javaspringrestjpa

提问by JeanValjean

I'm using SpringBoot and JPA to build a REST interface.

我正在使用 SpringBoot 和 JPA 来构建 REST 接口。

Now, I have a strange JSON returned for the list of products fetched from the database. Let's say that I have:

现在,我为从数据库中提取的产品列表返回了一个奇怪的 JSON。假设我有:

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "categoryId", nullable = false, updatable = false)
    private Category category;

    ...
}

@Entity
public class Category implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "category", cascade = CascadeType.DETACH)
    @OrderBy("name ASC")
    private List<Product> products = Collections.emptyList();

    ...
}

The JPA repository for the Productis defined as:

的 JPA 存储库Product定义为:

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findAll();
}

In my controller I have:

在我的控制器中,我有:

@Autowired
private ProductRepository productRepo;

@RequestMapping("/all-products", method = RequestMethod.GET)
public Map<String,Object> home() {
    Map<String,Object> model = new HashMap<String,Object>();
    model.put("products", productRepo.findAll());
    return model;
}

What is driving my crazy, is that if I try to call this service as follows:

让我发疯的是,如果我尝试按如下方式调用此服务:

$ curl localhost:8080/all-products

I get a recursive output due to the relationship between tables productand category, e.g.:

由于表product和之间的关系,我得到一个递归输出category,例如:

{"products":[{"id":1,"name":"Product1","category":
{"id":1,"name":"Cat1","products":[{"id":6,"name":"Product6","category":
{"id":1,"name":"Cat1","products":[{"id":6,"name":"Product6","category":
{"id":1,...

What am I doing wrong?

我究竟做错了什么?

回答by Xeon

You're not doing anything wrong (at least at the code level it's rather conceptual) - json serializer just goes like this:

您没有做错任何事情(至少在代码级别它是相当概念化的)- json 序列化程序如下所示:

  1. Product - serialize it, but wait - there is a category field, so serializer must serialize the category field
  2. Category - serialize it, but wait - there is a products field, so serializer must serialize each of the product in the list
  3. Product - because your collection contains the product & product contains category it goes in a endless loop untill a timeout.
  1. 产品 - 序列化它,但等待 - 有一个类别字段,因此序列化程序必须序列化类别字段
  2. Category - 序列化它,但是等等 - 有一个 products 字段,所以序列化程序必须序列化列表中的每个产品
  3. 产品 - 因为您的收藏包含产品和产品包含类别,所以它会无限循环,直到超时。

You must use a view or just skip it.

您必须使用视图或跳过它。

  1. Use @JsonView

  2. Use a view as a POJO Return new ProductViewthat has all fields of product and a reference (category) to new CategoryView(you can end at this point) that has collection of (products) new ProductViewWithoutReferences, and so on

  3. Use @JsonIgnoreon a collection of products

  1. 利用 @JsonView

  2. 使用视图作为 POJO 返回new ProductView,其中包含产品的所有字段和对new CategoryView(您可以在此时结束)的引用(类别),其中包含 (products) 的集合new ProductViewWithoutReferences,依此类推

  3. 用于@JsonIgnore一系列产品

And as a side note - if it's a @RestControllerand you're invoking "all-products" then it's a bit unusual to return something else than a list. Wrapping the response in a map is redundant. Many rest clients expect a list when they invoke list()method.

作为旁注 - 如果它是 a@RestController并且您正在调用“所有产品”,那么返回除列表之外的其他内容有点不寻常。将响应包装在地图中是多余的。许多休息客户端在调用list()方法时需要一个列表。

回答by so-random-dude

I know it's a bit late, but adding it here in case anybody faces the same problem. Here is another relevant answer I could find which discuss about similar topic

我知道这有点晚了,但在这里添加它以防万一有人面临同样的问题。这是我可以找到的另一个相关答案,其中讨论了类似的主题

https://stackoverflow.com/a/3359884/6785908

https://stackoverflow.com/a/3359884/6785908

quoting it here

在这里引用

Hymanson1.6 has annotation-based support for handling such parent/child linkage, see http://wiki.fasterxml.com/HymansonFeatureBiDirReferences.

You can of course already exclude serialization of parent link already using most JSON processing packages (Hymanson, gson and flex-json at least support it), but the real trick is in how to deserialize it back (re-create parent link), not just handle serialization side. Although sounds like for now just exclusion might work for you.

EDIT (April 2012): Hymanson 2.0now supports true identity references, so you can solve it this way also.

Hymanson1.6 对处理此类父/子链接具有基于注释的支持,请参阅 http://wiki.fasterxml.com/HymansonFeatureBiDirReferences

您当然可以排除已经使用大多数 JSON 处理包(Hymanson、gson 和 flex-json 至少支持它)的父链接的序列化,但真正的技巧是如何反序列化它(重新创建父链接),而不是只是处理序列化方面。虽然现在听起来只是排除可能对你有用。

编辑(2012 年 4 月):Hymanson 2.0现在支持真实身份引用,因此您也可以通过这种方式解决。

回答by Dapper Dan

Adding @JsonIgnore worked for me

添加@JsonIgnore 对我有用

@OneToMany(mappedBy = "policy")
@JsonIgnore
private List<Payment> payments;

@JeanValjean your are the best

@JeanValjean 你是最棒的