[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 {
@Id
@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<>();
...
}
class Parent {
@Id
@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<>();
}
and
@Entity
class Child {
private String name;
@ManyToOne
@JoinColumn(name="parent_id", referencedColumn="parent_id")
private Parent parent;
...
}
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();
}
}
@RequestMapping("/parents.json")
public class ParentListController {
@Autowired
private ParentDAO parentDAO;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public List
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 {
@Id
@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<>();
...
}
class Parent {
@Id
@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>
...
}
and
@Entity
class Child {
private String name;
@ManyToOne
@JoinColumn(name="parent_id", referencedColumn="parent_id")
@JsonBackReference
private Parent parent;
...
}
class Child {
private String name;
@ManyToOne
@JoinColumn(name="parent_id", referencedColumn="parent_id")
@JsonBackReference
private Parent parent;
...
}
Thank you! Simple and clear explanation.
ReplyDeletesuperb! exactly what i was looking for. thanks :)
ReplyDeleteIf i used Annotations like this only Child Object is able to retrieve ,
ReplyDeleteand i am facing new issue i.e
com.fasterxml.jackson.databind.JsonMappingException: Multiple back-reference properties with name 'defaultReference'
How to resolve this issue
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.
ReplyDeletealso superb! this is exactly what i was looking for. thank u very much :)
ReplyDelete2 years later and this is still a good piece of help.
ReplyDeleteThanks
Solved, thx
ReplyDeletethanks
ReplyDeletebut when i use this annotation, i cant get the value of propertie that i use it for
good example... thanks ......
ReplyDeletethanks a lot ...
ReplyDeleteThanks for the great simple solution
ReplyDeleteIn the meantime, I have to load a parent object while I am fetching the child from a child service exposed. In this case, I am not getting any parent object populated. Any suggestion there?
Thank you. I was looking for the solution for a while. My problem is solved now.
ReplyDeleteY:2017 and this still happens (needs annotation)... thanks !
ReplyDeleteThanks a lot it worked for me as well...
ReplyDeleteThanks a lot.. i also faced this issue
ReplyDeleteThank You very much.
ReplyDeleteThis solution worked for me !!
thank you this is worked for me :)
ReplyDeleteThank you. I got an output for this solution.
ReplyDeletethank you, simple and clear explanation
ReplyDeletethank you it is worked. but it is not retrieving child class attribute values. any suggestion
ReplyDeletethank u man,it really worked'
ReplyDelete
ReplyDeleteCould 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!!