주문 엔티티를 그대로 JSON으로 내려 줬더니 응답이 안 끝나고 서버가 뻗었다. 로그엔 끝없이 반복되는 스택.
com.fasterxml.jackson...JsonMappingException:
Infinite recursion (StackOverflowError)
양방향 연관이 서로를 계속 부른다
Order는 Member를 참조하고, Member는 자기 Order 목록을 참조하는 양방향 관계였다. Jackson이 Order를 직렬화하려고 Member를 펼치고, Member를 펼치다 다시 Order를 만나고, 그 Order가 또 Member를 부르고… 무한 루프에 빠져 스택이 터진 거다. 엔티티끼리 서로를 물고 있으면 직렬화가 빠져나올 출구가 없다.
엔티티를 그대로 내보내지 않기
급하면 한쪽에 @JsonIgnore를 붙여 끊을 수 있지만, 진짜 해법은 엔티티를 API 응답으로 직접 쓰지 않는 것이었다. 화면에 필요한 필드만 담은 응답 DTO를 따로 만들어 거기에 옮겨 담았다.
public record OrderResponse(Long id, String memberName, int amount) {
static OrderResponse from(Order o){
return new OrderResponse(o.getId(), o.getMember().getName(), o.getAmount());
}
}
DTO를 쓰니 순환도 사라지고, 실수로 내부 필드가 노출될 걱정도 없어졌다. 엔티티는 영속성 계층에, 응답은 응답 계층에. 경계를 나누는 게 결국 답이었다.