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 

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

 {"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序列化器就像这样:

  1. 产品 – 序列化它,但等待 – 有一个类别字段,因此序列化程序必须序列化类别字段
  2. 类别 – 序列化它,但等待 – 有一个产品字段,因此序列化程序必须序列化列表中的每个产品
  3. 产品 – 因为您的产品系列包含产品和产品包含的类别,它会无限循环,直到超时。

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

  1. 使用@JsonView

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

  3. 在产品集合上使用@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你是最好的