๐ด The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
java.lang.StackOverflowError: null
at com.devinhyderabad.entity.User.hashCode(User.java:20)
at java.base/java.util.AbstractList.hashCode(AbstractList.java:541)
at com.devinhyderabad.entity.Order.hashCode(Order.java:25)
at java.base/java.util.AbstractList.hashCode(AbstractList.java:541)
at com.devinhyderabad.entity.User.hashCode(User.java:20)
... (repeats hundreds of times)โก Quick Fix Works 80% of the time
Stop using @Data on JPA Entities. Use @Getter and @Setter instead.
@Entity
@Getter @Setter
public class User { ... }๐ง Why this Happens
Tap to expand the deep technical explanation
Lombok's @Data annotation automatically generates equals() and hashCode() methods that inspect every field. When two entities have a bidirectional relationship (User -> Orders -> User), calling user.hashCode() triggers order.hashCode(), which triggers user.hashCode() again, creating an infinite loop until the JVM stack overflows.
The HITEC City Parking Spot Analogy:
Imagine two mirrors facing each other. When you look into one mirror, you see an infinite tunnel of mirrors reflecting each other. Lombok's equals() tries to look all the way down the tunnel until it crashes.
๐ How to Reproduce Confirm this is your error
Use Lombok @Data on JPA entities with a bidirectional relationship, then save or find them. hashCode() recurses forever between the two entities and throws StackOverflowError.
๐ ๏ธ Solutions (3 Ways to Fix)
Replace @Data with @Getter and @Setter
๐ Use this on all JPA @Entity classes.
@Data generates equals() and hashCode() that include all fields. If User has a List of Orders, and Order has a User, they call each other infinitely. @Getter/@Setter avoid generating equals/hashCode.
// BAD
@Entity
@Data
public class User {
@OneToMany
private List<Order> orders;
}
// GOOD
@Entity
@Getter
@Setter
public class User {
@OneToMany
private List<Order> orders;
}Exclude the relationship field from equals/hashCode
๐ Use this if you still want Lombok to generate equals/hashCode, but safely.
Use @EqualsAndHashCode(exclude = "orders") to tell Lombok to ignore the bidirectional field.
@Entity
@Data
@EqualsAndHashCode(exclude = "orders")
public class User {
@OneToMany
private List<Order> orders;
}Implement equals/hashCode manually using ID
๐ Use this as the enterprise best practice for JPA entities.
Do not use Lombok for entity equality. Write custom equals() and hashCode() methods that only compare the primary key (@Id).
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
return id != null && id.equals(((User) o).getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}๐ Version Notes
Lombok interacts with Hibernate 5.
Lombok interacts with Hibernate 6. Same risk of StackOverflow.
๐ก๏ธ How to Prevent This Next Time
Never use @Data on JPA @Entity classes. Always use @Getter and @Setter, and implement custom equals/hashCode based on the ID.