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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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();

    ...
}

Product的JPA存储库定义为:

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

在我的控制器中,我有:

1
2
3
4
5
6
7
8
9
@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;
}

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

1
$ curl localhost:8080/all-products

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

1
2
3
4
{"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序列化程序如下所示:

  • 产品-序列化它,但等待-有一个类别字段,因此序列化程序必须序列化类别字段
  • category-序列化它,但wait-有一个products字段,因此序列化程序必须序列化列表中的每个产品
  • 产品-因为您的集合包含产品&产品包含类别,所以在超时之前,它将无休止地循环。
  • 你必须使用一个视图或者跳过它。

  • 使用@JsonView

  • 将视图用作POJO返回包含产品所有字段的new ProductView和包含(产品)new ProductViewWithoutReferences集合的new CategoryView的引用(类别),依此类推。

  • 在产品集合上使用@JsonIgnore

  • 作为旁注,如果它是一个@RestController,而你调用的是"所有产品",那么返回列表以外的东西有点不寻常。将响应包装在映射中是多余的。许多REST客户机在调用list()方法时都希望得到一个列表。


    添加@jsonignore对我有效

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

    @你是最棒的


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

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

    在这里引用

    Jackson 1.6 has annotation-based support for handling such
    parent/child linkage, see
    http://wiki.fasterxml.com/JacksonFeatureBiDirReferences.

    You can of course already exclude serialization of parent link already
    using most JSON processing packages (jackson, 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): Jackson 2.0 now supports true identity
    references, so you can solve it this way also.