순환 참조

박용민·2024년 1월 23일

Schedule Management 프로젝트를 진행하던중 처음보는 오류가 발생했다.

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)] with root cause

StackOverFlow? 자주 보던 오류였다. 보통 재귀 함수를 사용할때 탈출 조건에 만족하지 않아 무한 루프에 빠져 메모리 스택이 넘치는 현상이다
그런데 재귀 함수로 호출한 경우도 없고 딱히 문제가 될만한 부분이 있지 않았다. 그러던중 순환 참조라는것을 알게 되었다.

JPA 순환참조

  • 엔티티 간의 양방향 연관 관계에서 주로 발생하며 한 엔티티가 다른 엔티티를 참조하고, 다른 엔티티가 참조하는 상황에서 JSON 직렬화 시에 발생된다.
  • JPA 엔티티를 JSON으로 변환하려고 할 때 무한 루프에 빠져 스택 오버플로우가 발생할 수 있다.
  • @JsonIgnore나 @JsonManagedReference, @JsonBackReference, DTO를 사용해서 이를 해결할 수 있다.

JsonIgnore

  • Jackson 라이브러리에서 제공하는 어노테이션
  • 특정 필드나 메소드를 JSON 직렬화/역직렬화에서 제외시키는 역할
  • 주로 무한 순환 참조를 방지하기 위해 사용
@Entity
public class EntityA {

    @OneToMany(mappedBy = "entityA")
    @JsonIgnore
    private List<EntityB> entityBs;
}

@JsonManagedReference, @JsonBackReference

  • JsonIgnore와 같이 Jackson 라이브러리에서 제공하는 어노테이션
  • @JsonManagedReference : 양방향 연관 관계에서 한 쪽을 관리하는 역할
  • @JsonBackReference : JSON 직렬화 시에 역방향 참조를 무시하도록 지정합니다.
@Entity
public class EntityA {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "entityA")
    @JsonManagedReference
    private List<EntityB> entityBs;
}

@Entity
public class EntityB {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "entity_a_id")
    @JsonBackReference
    private EntityA entityA;
}

JsonIgnore 설정


0개의 댓글