Spring에서 REST API를 구현할 때, Spring JPA와 Jackson을 많이 사용한다. 이 환경에서 양방향 연관관계를 매핑할 때 무슨 문제가 있을까?
두 객체가 서로를 참조하면서 참조의 참조를 하는상황
@Entity
public class User {
@OneToMany(mappedBy = "user")
private List<Post> posts;
}
@Entity
public class Post {
@ManyToOne
private User user;
}
이 구조에서 User는 Post 리스트를 가지고 있고, Post는 다시 User를 참조
참조가 끝없이 반복되며, 결국 StackOverflowError 또는 API 무한 응답 대기 문제가 발생
해당 필드를 직렬화 대상에서 완전히 제외하는 방법
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
@ManyToOne
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
}
Jackson이 부모‒자식 관계를 인식하도록 표시
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "user")
@JsonManagedReference
private List<Post> posts;
}
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
@ManyToOne
@JoinColumn(name = "user_id")
@JsonBackReference
private User user;
}
같은 객체가 반복될 경우 중복 출력하지 않고 참조만 남기는 방식
@Entity
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class User {
@Id
private Long id;
private String name;
@OneToMany(mappedBy = "user")
private List<Post> posts;
}
@Entity
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class Post {
@Id
private Long id;
private String title;
@ManyToOne
private User user;
}
DTO(Data Transfer Object)는 엔티티(Entity)의 데이터를 클라이언트에 전달하거나 요청받기 위한 전용 객체
public class TagPlainDto {
private Long id;
private String name;
public static TagPlainDto fromEntity(TagPlain tag) {
return new TagPlainDto(tag.getId(), tag.getName());
}
// Constructor, Getter
}
방식 | 장점 | 단점 | 추천 상황 |
---|---|---|---|
@JsonIgnore | - 구현이 간단 - 즉시 순환 차단 | - 해당 필드가 JSON에서 빠짐 - 필요한 데이터는 별도 처리 필요 | 간단히 순환만 끊고 싶을 때 |
@JsonManagedReference / @JsonBackReference | - 부모→자식만 노출하며 순환 방지 - 일부 양방향 유지 가능 | - 관계가 많아지면 value 관리 복잡- 매핑 설정 포인트 증가 | 명확한 부모-자식 구조에서 순환만 제어할 때 |
@JsonIdentityInfo | - ID 기반 참조로 복잡한 순환 그래프도 안전 처리 | - JSON 가독성↓ (ID만 노출) - 추가 데이터 요청 필요 | 깊게 얽힌 연관 구조를 ID 중심으로 표현할 때 |
DTO 분리 | - 순환 참조 완전 제거 - 보안성·유연성·문서화 강점 | - DTO 클래스·매핑 로직 작성량 증가 - 유지보수 시 동기화 필요 | 실무 대형 프로젝트에서 안정적 API 설계가 필요할 때 |