4

I have the following method, which behind scenes uses Jackson to parse the list of entities to json:

@Controller
@RequestMapping("/user/")
public class EditarLugarController {    

@RequestMapping(value = "stores/{id}/branches", method = RequestMethod.GET)
public @ResponseBody List<Branch> renderBranchesPerStore(@PathVariable(value = "id") Integer id) {
    if(branches == null) {
        //get branches based on store's id 
    }
   return branches;
}

This method is called from the view through ajax using jquery

var idBranch = '${store.id}';
$.get("http://localhost:8080/myapp/user/stores/" + idBranch+ "/branches",
    function(data) {
        // show json objects in page
}); 

The problem is that when this method ends, it throws the following exception:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:639)

I tried removing the @PathVariable (returning some default value) and it works ok, but I need that parameter. Is there a workaroung to this issue?

EDIT: here's the branch code as requested, but again: I DONT think it's related to the issue because if I don't use @PathVariable it works ok, the list of Branches is parsed ok to json and sent to the view. Also, I'm using a Jackson plugin for Hibernate that tells Jackson not to parse attributes that are lazy loaded, to prevent exceptiosn

@Entity
@Table(name = "BRANCH")
public class Branch implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name="BRANCH_ID")
@GeneratedValue(strategy= GenerationType.TABLE)
private Integer id;

@Column(name = "DESCRIPTION")
@Size(max = 500)
private String description;

@Column(name="STREET")
@NotNull
@Size(max = 100)
private String street;

@Column(name="NUMBER")
@NotNull
@Size(max = 6)
private String number

@Column(name="FLOOR")
@Size(max = 3)
private String floor;

@Column(name="APT")
@Size(max = 10)
private String apt

@OneToMany(cascade = CascadeType.ALL, mappedBy="branch")
private List<BranchPhoto> photos;

@JoinColumn(name = "STORE_FK", referencedColumnName = "STORE_ID")
@ManyToOne(optional = false)
private Store store;

public Branch() {}

// getters & setters

}

EDIT: I've realized that even without PathVariable it thorws same exception, I must have tested that wrong. So the problem actually is for circular reference while parsing json

damian
  • 4,024
  • 5
  • 35
  • 53
  • 1
    can you show the rest of the code, response body and pathvariable work fine together – NimChimpsky Jun 24 '13 at 13:51
  • 2
    Are you knowingly writing to the response somewhere in **your** code? That could be the culprit, as Spring is also going to try to write out to the response. – nicholas.hauschild Jun 24 '13 at 13:55
  • Hi @NimChimpsky I added some code, I think all relevant code is there now. the only missing thing is the call to the dao to retrieve the entities from db. – damian Jun 24 '13 at 14:00
  • Hi @nicholas.hauschild I'm not writing in the response myself anywhere, but I think ResponseBody does that. what is weird is that without PathVariable it works ok, so there must be an issue with using it together with ResponseBody of a list of entities – damian Jun 24 '13 at 14:01
  • @Damian Can you post the `Branch` code? – vincentks Jun 24 '13 at 14:15
  • 1
    @Damian Do you happen to have a `Branch` property inside your `BranchPhoto` or `Store` classes? – vincentks Jun 24 '13 at 14:25
  • thanks guys! you were right, problem actually came from circular reference in the Branch entity (referencing Store) – damian Jun 24 '13 at 15:11

3 Answers3

4

As NimChimpsky said, problem was caused for circular references in the model, in class Branch. Besides using dtos to make serialization simple, another solution for those who do not want to use DTOs (like me) is to use some annotations to tell Jackson how to handle the attributes. these are the annotations needed:

In class Store, the attribute branches:

@OneToMany(mappedBy = "store", cascade = CascadeType.ALL)
@JsonManagedReference // this annotation prevents the exception
private List<Branch> branches

And in class Branch, in the attribute store:

@JoinColumn(name = "LUGAR_FK", referencedColumnName = "LUGAR_ID")
@ManyToOne(optional = false)
@JsonBackReference // this annotation prevents the exception
private Lugar lugar;
damian
  • 4,024
  • 5
  • 35
  • 53
  • 1
    For me the error happened when I returned entities with `@OneToMany` and `@ManyToMany` annotation as JSON in contorllers - circular containment of the JSON objects caused IllegalStateException. This annotation solved the problem. Thanks! – Croo Jan 05 '15 at 09:30
  • I faced the same circular containment issue!! Thanks a lot :) – Anusha Aug 16 '17 at 09:45
3

Does Branch contain non-primtives ?

The serialziation of that looks to be the culprit ...specifically a circular reference.

I normally create form specific dto's and keep the serialziation simple.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • it does contain non-primitives, but I don't think that's the issue for 2 reasons: 1) if I don't use PathVariable (the id parameter) and return any random set of Branches it works ok. 2) I'm also using ResponseBody to parse other entites with non-primitives using Jackson and it works fine too. – damian Jun 24 '13 at 14:11
  • @Damian Branch definitely has no circular reference in the json ? ResponseBody and pathvariable work fine together normally, they are unrelated ... what is ID used for then, as that is passed into method, show the method. – NimChimpsky Jun 24 '13 at 14:13
  • you were right @NimChimpsky, the problem was due to circular reference. I fixed it using the following annotations in the entities: JsonManagedReference and JsonBackReference. Can you update your answer including this or other way to solve circular reference? – damian Jun 24 '13 at 15:10
  • @Damian I have never used those annotations I just create DTO (transfer object) from the different entities and output that as json. – NimChimpsky Jun 24 '13 at 15:14
0

I know this was answered a while ago, but it helped me to find some workaround.

In order to eliminate the circular references to value that I didn't needed anyway. I created inner class with only fields that I needed (none of those were with reference one/many to one/many) and wrote the inner private class to ResponseBody

Khobar
  • 486
  • 7
  • 20