Кейс: StackOverflowError из-за Lombok @Data на связанных сущностях
Order и OrderItem связаны двусторонне: у Order список items, у OrderItem ссылка на order. Обе сущности помечены @Data. Логирование order.toString() падает со StackOverflowError.
Причина: сгенерированный toString() у Order вызывает toString() каждого OrderItem из списка, а тот вызывает toString() у своего order — и по кругу. То же самое с equals()/hashCode(), если они попадают в сравнение через коллекции. В юнит-тестах с одной сущностью без второй стороны связи это не всплывает — граф просто не загружен целиком.
@Entity @Data public class Order { @Id private Long id;
@OneToMany(mappedBy = "order") private List items; }
@Entity @Data public class OrderItem { @Id private Long id;
@ManyToOne private Order order; }
Исправление — точечно исключить обратную ссылку из toString/equals/hashCode:
@ToString.Exclude @EqualsAndHashCode.Exclude private Order order;
Спросят: почему это не поймали на code review раньше? Потому что StackOverflow ловит только сценарий, где реально загружен граф с обеих сторон — на одиночной сущности или с моками этого не происходит.
Lombok на JPA-сущностях с двусторонними связями почти всегда нужно точечно ограничивать полями, а не тянуть весь граф в equals/hashCode/toString.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки
· 21.08
на jpa-сущностях лучше вообще не ставить @Data, а кидать @Getter @Setter и писать equals/hashCode руками по одному @Id — скучно, зато не ловишь сюрпризы при любом графе связей. @ToString.Exclude лечит конкретный симптом, но через полгода кто-то добавит ещё одну двустороннюю связь и наступит на те же грабли. у нас после третьего такого инцидента просто запретили @Data на энтитях archunit-тестом, и всё, вопрос закрыт навсегда
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён