REST控制器中具有一对多关系的实体的递归JSON视图
我正在使用SpringBoot和JPA来构建REST接口。
现在,我为从数据库中提取的产品列表返回了一个奇怪的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 products = Collections.emptyList(); ... }
产品的JPA存储库定义为:
public interface ProductRepository extends JpaRepository { List findAll(); }
在我的控制器中,我有:
@Autowired private ProductRepository productRepo; @RequestMapping("/all-products", method = RequestMethod.GET) public Map home() { Map model = new HashMap(); model.put("products", productRepo.findAll()); return model; }
让我疯狂的是,如果我尝试按如下方式调用此服务:
$ curl localhost:8080/all-products
由于表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,...
我究竟做错了什么?
你没有做错任何事情(至少在代码级别它是相当概念性的) – json序列化器就像这样:
- 产品 – 序列化它,但等待 – 有一个类别字段,因此序列化程序必须序列化类别字段
- 类别 – 序列化它,但等待 – 有一个产品字段,因此序列化程序必须序列化列表中的每个产品
- 产品 – 因为您的产品系列包含产品和产品包含的类别,它会无限循环,直到超时。
您必须使用视图或只是跳过它。
-
使用
@JsonView
-
将视图用作POJO将包含产品的所有字段和引用(类别)的
new ProductView
返回到new CategoryView
(此时可以结束),其中包含(产品)new ProductViewWithoutReferences
集合,依此类推 -
在产品集合上使用
@JsonIgnore
作为旁注 – 如果它是@RestController
并且你正在调用“所有产品”那么返回其他东西而不是列表有点不寻常。 在地图中包装响应是多余的。 许多其他客户端在调用list()
方法时需要一个列表。
我知道这有点晚了,但是如果有人面临同样的问题,请在此处添加。 这是我可以找到的另一个相关的答案,讨论类似的主题
https://stackoverflow.com/a/3359884/6785908
在这里引用它
Jackson 1.6具有基于注释的支持,用于处理此类父/子链接,请参阅http://wiki.fasterxml.com/JacksonFeatureBiDirReferences 。
您当然已经使用大多数JSON处理包(jackson,gson和flex-json至少支持它)排除了父链接的序列化,但真正的诀窍在于如何反序列化它(重新创建父链接),而不是只是处理序列化方面。 虽然现在的声音只是排除可能对你有用。
编辑(2012年4月): jackson2.0现在支持真正的身份参考 ,所以你也可以这样解决它。
添加@JsonIgnore对我有用
@OneToMany(mappedBy = "policy") @JsonIgnore private List payments;
@JeanValjean你是最好的