순환 참조

TODO 리스트 토이 프로젝트를 해보다가 순환 참조 문제가 발생했다.

순환참조란, 참조하는 대상이 서로 물려 있어서 참조할 수 없게 되는 현상을 말한다.

TodoListInfo.java

@Entity
@Getter
@Builder
@NoArgsConstructor @AllArgsConstructor
public class TodoListInfo {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long code;

    @OneToOne
    private Member writer;

    @OneToMany(mappedBy = "todoListInfo", cascade = CascadeType.ALL)
    private List<Todo> todoList = new ArrayList<>();
}

Todo.java

@Entity
@Getter
@Builder
@NoArgsConstructor @AllArgsConstructor
public class Todo {
    @Column(name = "todo_id")
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "todo_list_info_code")
    private TodoListInfo todoListInfo;

    private String description;

    private boolean isCompleted;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Asia/Seoul")
    private LocalDateTime startTime;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Asia/Seoul")
    private LocalDateTime endTime;

}

위 두 객체를 보면 TodoListInfo 에서는 List<Todo> 를 통해, Todo 에서는 TodoListInfo 를 통해 서로 참조하고 있다.

만약 JSON 응답으로 이 관계를 그대로 보내게 되면 순환 참조 문제가 발생한다.

예를 들어, TodoListInfo 의 형식 그대로 응답으로 내보냈다고 해보자.

그러면 TodoListInfoList<Todo> 에서 각각의 TodoTodoListInfo 를 참조할 것이다. 이 방식이 계속 반복되게 된다.

이러한 순환 참조를 막기 위한 2가지 방법을 알아보자.

@JsonIgnore

Todo 클래스의 TodoListInfo 필드에 @JsonIgnore 애노테이션을 추가해준다.

이 애노테이션을 사용 시 조회할 경우 해당 필드를 조회하지 않는다.

DTO

해당 응답에 따른 DTO를 생성하여 필요한 데이터만 담아서 반환하면 순환 참조 문제를 방지할 수 있다.

ReadTodoListDto.java

TodoDto.java

TodoListInfo 를 조회할 때, DTO를 이용하여 필요한 정보만 담아줌으로써 순환 참조를 방지한다.

TodoDto 에는 TodoListInfo 에 대한 참조가 빠져있다.

Last updated