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
Recursive JSON view of an entity with one-to-many relationship in REST controller
提问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 Product
is 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 product
and 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 序列化程序如下所示:
- Product - serialize it, but wait - there is a category field, so serializer must serialize the category field
- Category - serialize it, but wait - there is a products field, so serializer must serialize each of the product in the list
- Product - because your collection contains the product & product contains category it goes in a endless loop untill a timeout.
- 产品 - 序列化它,但等待 - 有一个类别字段,因此序列化程序必须序列化类别字段
- Category - 序列化它,但是等等 - 有一个 products 字段,所以序列化程序必须序列化列表中的每个产品
- 产品 - 因为您的收藏包含产品和产品包含类别,所以它会无限循环,直到超时。
You must use a view or just skip it.
您必须使用视图或跳过它。
Use
@JsonView
Use a view as a POJO Return
new ProductView
that has all fields of product and a reference (category) tonew CategoryView
(you can end at this point) that has collection of (products)new ProductViewWithoutReferences
, and so onUse
@JsonIgnore
on a collection of products
利用
@JsonView
使用视图作为 POJO 返回
new ProductView
,其中包含产品的所有字段和对new CategoryView
(您可以在此时结束)的引用(类别),其中包含 (products) 的集合new ProductViewWithoutReferences
,依此类推用于
@JsonIgnore
一系列产品
And as a side note - if it's a @RestController
and 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 你是最棒的