I have two JPA entities with a @ManyToMany relationship, for example Student and Course, something like that:
Student Entity:
@ManyToMany
List<Course> courses;
Course Entity:
@ManyToMany
List<Student> students;
What is the best way/pattern to implement a Spring REST controller which returns students and courses? I would like to see inside the JSON Student the list of the courses enrolled, but stopping the recursion deep to the first level (to avoid a stack overflow). I would like the same for the JSON Course. In other words, I would like to see a student with a list of enrlolled courses inside, but do not want the list of students inside every course again, to avoid recursion. I know about @JsonBackReference an so on, but this is not the case because I want to see the lists in both the JSON’s entities involved.
I know there are already some topics about this problem on stackoverflow, but I didn’t find anything really definitive.
Could anybody give me some hints?
Best regards,
Bruno
4
Answers
You can make projections to prevent the StackOverFlowError errors like:
And for StudentRepository:
With the query above, you will get list of the students with enrolled courses. Please correct me if i misunderstood the problem.
IMO, the best solution for this problem would be to make two different read models for each case, including its own endpoint.
This means that you would have a read model (and endpoint) for students with a list of their enrolled courses, and a separate read model for courses and their enrolled students.
There’s no real reason why these two views should be coupled so tightly that they cause the problems that you describe, and so I would simply decouple them.
So, something like:
while this does cause a bit of model bloat, it also forces you to think about the design of your API a lot more – note that I’ve called the third class above a
CourseEnrollment
– which is not necessarily aCourse
! Similarly, does a response containing Student really need to list all the fields of the courses that the student is enrolled in? Or would a subset of the data as a separate read-view suffice?IMO this added model bloat is worth the design tradeoffs.
You could try @JsonIgnoreProperties("field name") (where you would put @JsonManagedReference/@JsonBackReference), it will omit the field name so no recursion in json response…
But long term a DTO is a nice solution, since it would return that instead of the entity, so changes in entity won’t break api that much.
To handle the recursion issue you can make use of Jackson’s
@JsonManagedReference
and@JsonBackReference
annotations. These annotations allow you to control the serialization and deserialization process to prevent infinite recursion.Here is the example below how you can implement:
Student Entity
Course Entity
In the Student entity, we use
@JsonManagedReference
to mark the courses field. This indicates that the serialization of the courses list will be managed by the Student entity.In the Course entity, we use
@JsonBackReference
to mark the students field. This indicates that the serialization of the students list will be handled by the opposite side of the relationship (i.e., the Student entity). This prevents the recursion issue by breaking the cycle.