I’m attempting to create a many to many relationship. I have a table ‘library_branch’ and i want to join ‘BookCopies’ which contains ‘bookId’, ‘branchId’ and ‘noOfCopies’. I have an error ErrorMvcAutoConfiguration$StaticView
. I’m not sure where I’m causing this infinite recursion, any help will be greatly appreciated.
2021-11-26 14:54:43.544 ERROR 22348 --- [nio-8080-exec-1] s.e.ErrorMvcAutoConfiguration$StaticView : Cannot render error page for request [/api/branch] and exception [Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.example.demo.branch.Branch["inventory"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.inventory.Inventory["branch"]->com.example.demo.branch.Branch["inventory"]
InventoryId.java
package com.example.demo.inventory; ... @Data @AllArgsConstructor @NoArgsConstructor @Embeddable public class InventoryId implements Serializable { @Column(name = "book_id") private int bookId; @Column(name = "branch_id") private int branchId; }
Inventory.java
package com.example.demo.inventory; ... @Entity(name="Inventory") @Table(name = "tblBookCopies") public class Inventory { @EmbeddedId private InventoryId id; @ManyToOne(fetch = FetchType.LAZY) @MapsId("branch_id") private Branch branch; @ManyToOne(fetch = FetchType.LAZY) @MapsId("book_id") private Book book; @Column(name="no_of_copies") private int qty; public Inventory( Branch branch, Book book, int qty) { this.id = new InventoryId(branch.getId(),book.getId()); this.branch = branch; this.book = book; this.qty = qty; } ... }
Branch.java
package com.example.demo.branch; ... @Entity(name="Branch") @Table(name="tblLibraryBranch") public class Branch { @Id @Column(name="id") private int id; @Column(name="name") private String name; @Column(name="address") private String address; @OneToMany(mappedBy = "branch", cascade = CascadeType.ALL, orphanRemoval = true) private Set<Inventory> inventory = new HashSet<>(); ... }
Advertisement
Answer
The problem is that your Inventory
points to Branch
and your Branch
has a reference to Inventory
. The problem is coming from Jackson, you need to explain it how to follow these references that form a circular dependency.
Option 1)
Don’t use Entities for serialization. Normally you don’t want to expose the DB entities – these should be internal objects. If you map them to some DTO representation and serialize that the problem will disappear.
Option 2)
Explain to Jackson how to follow those references – you need to look at JsonManagedReference
and JsonBackReference
.
In your case you need to try something like (but also check number 7 in this blogpost):
@Entity(name="Inventory") @Table(name = "tblBookCopies") public class Inventory { ... @ManyToOne(fetch = FetchType.LAZY) @MapsId("branch_id") @JsonManagedReference // <-------- THIS private Branch branch; ... }
and
@Entity(name="Branch") @Table(name="tblLibraryBranch") public class Branch { ... @OneToMany(mappedBy = "branch", cascade = CascadeType.ALL, orphanRemoval = true) @JsonBackReference // <--------- THIS private Set<Inventory> inventory = new HashSet<>(); ... }