【问题标题】:Recursive JSON view of an entity with one-to-many relationship in REST controllerREST 控制器中具有一对多关系的实体的递归 JSON 视图
【发布时间】:2015-10-06 13:29:12
【问题描述】:

我正在使用 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();

    ...
}

Product 的 JPA 存储库定义为:

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

由于表 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,...

我做错了什么?

【问题讨论】:

    标签: java spring rest jpa


    【解决方案1】:

    你没有做错任何事(至少在代码级别它是相当概念性的) - json 序列化器就像这样:

    1. Product - 序列化它,但是等待 - 有一个类别字段,所以序列化程序必须序列化类别字段
    2. Category - 序列化它,但是等等 - 有一个 products 字段,所以序列化程序必须序列化列表中的每个产品
    3. 产品 - 因为您的收藏包含产品并且产品包含类别,所以它会无限循环直到超时。

    您必须使用视图或直接跳过它。

    1. 使用@JsonView

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

    3. 在产品集合上使用@JsonIgnore

    附带说明 - 如果它是 @RestController 并且您正在调用“所有产品”,那么返回列表以外的其他内容有点不寻常。将响应包装在地图中是多余的。许多 REST 客户端在调用 list() 方法时期望得到一个列表。

    【讨论】:

    • @JeanValjean 您只是注释了在序列化发生时应该跳过的类的字段。 @JsonIgnore private List&lt;Product&gt; products...
    【解决方案2】:

    我知道这有点晚了,但在这里添加它以防有人遇到同样的问题。 这是我能找到的另一个相关答案,讨论了类似的话题

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

    在这里引用

    Jackson 1.6 具有基于注释的支持来处理此类 父/子链接,见 http://wiki.fasterxml.com/JacksonFeatureBiDirReferences.

    您当然已经可以排除父链接的序列化 使用大多数 JSON 处理包(jackson、gson 和 flex-json at 最少支持它),但真正的诀窍在于如何反序列化它 (重新创建父链接),而不仅仅是处理序列化方面。虽然 听起来现在只是排除可能对您有用。

    编辑(2012 年 4 月):Jackson 2.0 现在支持真正的identity references,因此您也可以通过这种方式解决它。

    【讨论】:

      【解决方案3】:

      添加@JsonIgnore 对我有用

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

      @JeanValjean 你是最棒的

      【讨论】:

        猜你喜欢
        • 2019-07-13
        • 2020-05-09
        • 2014-04-28
        • 1970-01-01
        • 2019-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多