如何将@RestController(Spring)与子对象列表一起使用

时间:2018-11-21 14:47:14

标签: spring rest spring-restcontroller

我正在尝试使用Spring创建 REST 服务。 一切正常,直到我尝试将对象列表(CartItem)添加到我的主对象(Cart)中。

这是我的主要对象

@Entity
@Table(name="cart")
public class Cart implements Serializable{
   ...
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Id
   @Column(name="id")
   private Integer id;  

   /*when I add this I get the error. If I remove this, the 
   REST service works*/
   @OneToMany(mappedBy="cart", fetch = FetchType.EAGER)
   private List<CartItem> cartItems; 

   //getter, setter, constructors, other fields ecc.
}

这是列表中的对象:

@Entity
@Table(name="cart_item")
public class CartItem implements Serializable{
   ...
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Id
   @Column(name="id")
   private Integer id; 

   @OneToOne(targetEntity = Product.class, cascade = CascadeType.ALL)
   @JoinColumn(referencedColumnName="productId", name="product_id" )    
   private Product product;     

   @ManyToOne 
   @JoinColumn(name="cart_id", nullable=false)     
   private Cart cart;

  //getter, setter, constructors, other fields ecc.
}

这是我的控制人

@RestController
@RequestMapping(value="rest/cart")
public class CartRestController {
  ...
    @RequestMapping(value = "/", method = RequestMethod.GET) 
    public List<Cart> readAll() { 
        return cartService.read(); 
    }
 ...
}

我收到此错误:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path 
[/webstore] threw exception [Request processing failed; nested exception
 is org.springframework.http.converter.HttpMessageNotWritableException: 
Could not write JSON: Infinite recursion (StackOverflowError); nested
 exception is com.fasterxml.jackson.databind.JsonMappingException: 
Infinite recursion (StackOverflowError) (through reference chain:...

我想我必须以一种特殊的方式来管理Cart对象内的List,也许是因为我使用的是JPA,但我仍然没有在Internet上找到解决方案。 谁能帮我吗?

2 个答案:

答案 0 :(得分:2)

这是序列化递归问题,因为CartItem具有回溯到Cart的双向映射而发生。

  • 购物车被序列化为JSON
    • 其中的所有CartItems都序列化为JSON
      • CartItem中的Cart属性被序列化为JSON
        • 购物车中的CartItems序列化为json等,等等。

您可能希望通过使用@JsonIgnore批注将CartItem.cart字段从序列化中排除。


如果直接在Web服务内部使用JPA实体,那么将太多的信息暴露给外界很容易。杰克逊实际上有一个称为JsonView的有用功能,它允许您定义要公开的属性,甚至可以根据需要针对每个Web服务调用对其进行定制。

答案 1 :(得分:1)

永远不会结束列表?您是说stackOverFlow异常吗?

如果情况就像我说的那样,那么您应该检查诸如访存类型和实体的toString()或equal()方法之类的东西。

例如,存在一个名为A和B的实体,它们之间的关系是一对多(A是一个)。如果将两个fetchType都配置为Eager,则当jpa查询A时,它也会查询B。但是B也包含A,因此jpa会再次查询A。这种循环会导致stackOverFlow。

顺便说一句,如何提供有关您的问题的更多信息(例如“异常”名称)?我很难为您提供具体的解决方案,我所能做的就是告诉您我以前见过的一些经验。


好吧,我用SpringBoot 2.1.0和MySql创建了一个小项目。

这是我的购物车

public class CartItem {
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id
    @Column(name="id")
    private Integer id;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name="cart_id", nullable=false)
    private Cart cart;
}

和我的购物车:

public class Cart {
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Id
    @Column(name="id")
    private Integer id;

    @OneToMany(mappedBy="cart", fetch = FetchType.EAGER)
    private List<CartItem> cartItems;
}

控制器与您编写的相同。在CartItem的购物车文件中添加@JsonIgnore之后,循环循环结束(在执行此操作之前,程序确实出现了循环循环问题)。

每次将jpa与@ oneToMany,@ ManyToOne或@ManyToMany一起使用时,都应谨慎对待此问题。实例化对象,打印对象或类似对象时可能会发生这种循环引用情况。有很多解决方法,例如将获取类型更改为LAZY,添加@JsonIgnore,覆盖toString()和equal()方法。