问题描述
我正在使用 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<Product> products = Collections.emptyList();
...
}
对于JPA的存储库Product
的定义为:
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findAll();
}
在我的控制器中,我有:
@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;
}
让我发疯的是,如果我尝试按如下方式调用此服务:
$ 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,...
我究竟做错了什么?
1楼
你没有做错任何事(至少在代码级别它是相当概念化的) - json 序列化程序就像这样:
- 产品 - 序列化它,但等待 - 有一个类别字段,因此序列化程序必须序列化类别字段
- Category - 序列化它,但是等等 - 有一个 products 字段,所以序列化程序必须序列化列表中的每个产品
- 产品 - 因为您的集合包含产品和产品包含类别,所以它会无限循环,直到超时。
您必须使用视图或跳过它。
使用
使用视图作为POJO返回
new ProductView
有产品的各个领域,并参考(类别),以new CategoryView
(你可以在此时结束),其具有的(产品)征收new ProductViewWithoutReferences
,等等在产品集合上使用
@JsonIgnore
作为旁注 - 如果它是@RestController
并且您正在调用“所有产品”,那么返回除列表之外的其他内容有点不寻常。
将响应包装在地图中是多余的。
许多休息客户端在调用list()
方法时需要一个列表。
2楼
我知道这有点晚了,但在这里添加它以防万一有人面临同样的问题。 这是我可以找到的另一个相关答案,其中讨论了类似的主题
在这里引用
1.6 对处理此类父/子链接具有基于注释的支持,请参阅 。
您当然可以排除已经使用大多数 JSON 处理包(jackson、gson 和 flex-json 至少支持它)的父链接的序列化,但真正的技巧是如何反序列化它(重新创建父链接),而不是只是处理序列化方面。 虽然现在听起来只是排除可能对你有用。
编辑(2012 年 4 月): 现在支持真实,因此您也可以通过这种方式解决。
3楼
添加@JsonIgnore 对我有用
@OneToMany(mappedBy = "policy")
@JsonIgnore
private List<Payment> payments;
@JeanValjean 你是最棒的