It\'s my first question here on stack, so please be gentle :D
I\'m trying to create hibernate OneToMany relationship. When I try to fetch some data from my DB, I\'m
I replaced the @Data annotation with Lombok's @Getter and @Setter annotations
Circular dependency can originate from Lombok's toString()
autogenerated method, if you use @Data
complex annotation. To exclude your circular dependecy for a certain field:
@Entity
@Data
public class Team {
...
@ToString.Exclude
@ManyToOne
private League league;
}
The only way it can throw an StackOverFlow is when your Team's League is accessed recursively....
Team to League to Team to League
I'm guessing there's some function trying to convert your objects into some other representation reflectively or recursively resulting in an infinite loop.
I had this error because I was parsing a list of objects mapped on both sides @OneToMany
and @ManyToOne
to json using jackson which caused an infinite loop.
If you are in the same situation you can solve this by using @JsonManagedReference
and @JsonBackReference
annotations.
Definitions from API :
JsonManagedReference (https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html) :
Annotation used to indicate that annotated property is part of two-way linkage between fields; and that its role is "parent" (or "forward") link. Value type (class) of property must have a single compatible property annotated with JsonBackReference. Linkage is handled such that the property annotated with this annotation is handled normally (serialized normally, no special handling for deserialization); it is the matching back reference that requires special handling
JsonBackReference: (https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html):
Annotation used to indicate that associated property is part of two-way linkage between fields; and that its role is "child" (or "back") link. Value type of the property must be a bean: it can not be a Collection, Map, Array or enumeration. Linkage is handled such that the property annotated with this annotation is not serialized; and during deserialization, its value is set to instance that has the "managed" (forward) link.
Example:
Owner.java:
@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;
Car.java:
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;
Another solution is to use @JsonIgnore
which will just set null to the field.
I struggled a very long time and thought it's a problem from Kotlin why it throws an Stackoverflow Exception. At the end it was Jackson, which is used by Spring Hibernate and causese the Stackoverflow.
You can solve that by setting @JsonIgnoreProperties
on both sides. Example:
public class ProductEntity implements Serializable {
private List<ProductPriceEntity> refProductPriceEntities = new ArrayList<>();
@OneToMany(
mappedBy = "product",
fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true,
targetEntity = ProductPriceEntity.class)
@JsonIgnoreProperties(value = "product", allowSetters = true)
public List<ProductPriceEntity> getRefProductPriceEntities() {
return refProductPriceEntities;
}
public void setRefProductPriceEntities(List<ProductPriceEntity> refProductPriceEntities) {
this.refProductPriceEntities = refProductPriceEntities;
}
}
and finally the other side, which caused the stackoverflow exception.
public class ProductPriceEntity {
private ProductEntity product;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false),
@JoinColumn(name = "product_version_id", referencedColumnName = "version_id", nullable = false)
})
@JsonIgnoreProperties(value = "refProductPriceEntities", allowSetters = true)
public ProductEntity getProduct() {
return product;
}
public void setProduct(ProductEntity product) {
this.product = product;
}
}
For me, Both hashCode and toString default implementation provided by Lombok was causing this issue.
You can use this annotation to exclude members for both equalsAndHasCode with single annotation:
@EqualsAndHashCode(exclude = {"certificates", "payment"})
Also if you want to exclude just members from equals method, Lombok provide : @ToString.Exclude
@ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "shipment")
private Set<Certificate> certificates;