[TIL] 순환 참조 문제 (Infinite Recursion in JSON Serializat…

2025-05-10 TIL

📝 TIL (Today I Learned)
🔗 원본 이슈: #54
📅 작성일: 2025-05-10
🔄 최종 수정: 2025년 05월 22일


🍀 새롭게 배운 것

  • 순환 참조 문제 (Infinite Recursion in JSON Serialization)

오늘은 API 응답을 구성하는 과정에서 발생한 무한 재귀 직렬화 오류를 해결하며 순환 참조(Circular Reference)에 대해 학습했다. 문제의 핵심은 Entity 간 양방향 참조가 존재할 때, JSON 직렬화 과정에서 객체 간 호출이 끝없이 반복되어 StackOverflowError가 발생하는 현상이었다.

⚠️ 문제 상황

  • PeerReviewPost
  • PostMember, postMembers
  • PostMember → 다시 Post

이렇게 서로 참조하는 구조로 인해 JSON 직렬화 중 무한 루프가 발생했다.

🔍 해결 방법

✅ 1. DTO 패턴 사용 (권장)

  • 가장 바람직한 해결책은 Entity를 그대로 반환하지 않고, 필요한 정보만 담은 Response DTO를 만들어 응답하는 방식이다.
  • 예를 들어 PeerReviewResponse에서는 Post 전체 객체를 넘기지 않고, postId, postTitle만 넘기도록 변경했다.
  • 같은 방식으로 UserReviewCommentResponse도 수정했다.

이렇게 DTO를 사용하면 다음과 같은 장점이 있다:

  • 불필요한 Entity 참조 제거 → 순환 참조 문제 해결
  • 필요한 데이터만 전달 → 응답 성능 향상
  • Entity와 API 응답 로직 분리 → 유지보수성 향상
  • 보안상 안전 (내부 필드 노출 방지)

🛠️ 2. Jackson 어노테이션 사용 (보완적/참고용)

  • 만약 어쩔 수 없이 Entity를 직접 반환해야 한다면 @JsonManagedReference, @JsonBackReference 또는 @JsonIgnore를 사용하는 방식도 있다.
// Post.java
@OneToMany(mappedBy = "post")
@JsonManagedReference
private List<PostMember> postMembers;

// PostMember.java
@ManyToOne
@JoinColumn(name = "post_id")
@JsonBackReference
private Post post;
  • 하지만 이 방법은 API와 Entity 계층이 강하게 결합되므로, 장기적으로는 유지보수나 테스트 측면에서 불리하다.

오늘의 핵심 교훈: Entity는 절대 API 응답용으로 직접 사용하지 말자! Response DTO를 따로 만들어 사용하는 습관이 순환 참조를 방지하고, 더 안전하고 명확한 API를 만들 수 있는 길이다.