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<>();
...
}
CodePudding user response:
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<>();
...
}