Search code examples
springrestspring-restcontroller

How to use @RestController (Spring) with a child List of object


I'm trying to create a REST service with Spring. Everything works until I try to add a List of object (CartItem) to my main object (Cart).

This is my main object

@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.
}

This is the object inside the List:

@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.
}

This is my controller

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

I get this error:

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:...

I suppose that I had to manage the List inside the Cart object in a particular manner, maybe because i'm using JPA, but I still didn't find a solution on the internet. Can anyone help me?


Solution

  • This is a serialization recursion problem, it happens because CartItem has a bidirectional mapping back to Cart. So what happens is that

    • a Cart gets serialized to JSON
      • all the CartItems inside it get serialized to JSON
        • the Cart property inside CartItem get serialized to JSON
          • the CartItems inside the cart get serialized to json, etc. etc.

    You will probably want to exclude the CartItem.cart field from serialization by marking it with the @JsonIgnore annotation.


    It is only too easy to expose far too much information to the outside world if you use JPA entities directly inside your webservices. Jackson actually has a useful feature called a JsonView which allows you to define which properties get exposed, you can even tailor it per webservice call if you want.