A couple of days back, I ran into an interesting error while retrieving persisted entities as JSON  in SpringMVC:
[Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)... I had to do some poking around and reading up on documentation to figure out how to fix it.
As it turned out, the fix wasn't that complex and the culprit was Jackson : the Java-JSON processor being used to transform the retrieved Java entity to a JSON representation.
The error occurs when you try to retrieve an entity that has a bi-directional @OneToMany relationship with another entity.
For example if we have a Parent to Child entity with the Parent entity having a one to many relationship with Child . i.e:
@Entity
class Parent {
@Column(name="parent_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Parent wife;
@OneToMany(mappedBy="parent" cascade = CascadeType.ALL)
private Collection<Child>children = new ArrayList<>();
@Entity
class Child {
private String name;
@ManyToOne
@JoinColumn(name="parent_id", referencedColumn="parent_id")
private Parent parent;
Retrieving Parent entity in your SpringMVC controller might look like this:
@Controller
@RequestMapping("/parents.json")
public class ParentListController {
@Autowired
private ParentDAO parentDAO;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public List getParents() {
return parentDAO.getAll();
}
And the above code would give the error:
nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)
The fix is to get Jackson to be able to handle bi-directional references. And this is done by using two Annotations: @JsonManagedReference and @JsonBackReference .
@JsonManagedReference is used to annotate the inverse side while @JsonBackReference maps the owning side of the relationship.
And updated version of the Parent and Child entity that would work would then be:
@Entity
class Parent {
@Column(name="parent_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Parent wife;
@OneToMany(mappedBy="parent" cascade = CascadeType.ALL)
@JsonManagedReference
private Collection<Child> children = new ArrayList<>();
@Entity
class Child {
private String name;
@ManyToOne
@JoinColumn(name="parent_id", referencedColumn="parent_id")
@JsonBackReference
private Parent parent;
In this example, I cannot find a "referencedColumn", only a "referencedColumnName". Also, when I use @JsonBackReference and @JsonManagedReference, I am prompted to import either "..fasterxml.Jackson.." or "..codehaus.Jackson..". Does the import make any difference? And also, when you say "parent_id", what is the convention for that? Is it "class_id", "class_", or just ""? Sorry I have so many questions, but this post seems like it will solve my problem if you can help me out.
Could someone please reclarify why this is needed, I have seen MANY video tutorials on @OneToMany and @ManyToOne and none of those used these annotations. I was getting desperate because I was having this error for about 6 hours. It was resolved using these two annotations. THANKS A LOT to the author!!
  • How To Use .call(), .apply() and .bind() In Javasc...
  • Javascript is not Java. Deal with it
  • Fixing org.springframework.http.converter.HttpMess...
  • Enum in Java.
  •