@ManyToOne 과 @OneToMany 의 양방향 관계 매핑을 하여 대댓글을 구현하는데 만난 이슈를 적어보려합니다.
먼저 클라이언트에서 서버로 데이터를 주고 받을 수 있는 방법은 직렬화를 통해서 데이터를 주고 받고 한다.
spring에선 jackson 라이브러리를 활용하여 json으로 통신이 가능하다.
jackson은 공개 필드에 관해서만 직렬화를 가능하게 해준다.
비공개 필드는 Getter을 활용하고 Setter로 접근하여 역직렬화를 시도한다.
참조: https://www.baeldung.com/jackson-field-serializable-deserializable-or-not
이슈의 과정을 살펴보자.
대댓글과 같은 계층 구조를 아래와 같이 연관관계 설정을 하였다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID")
private Comment parent;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
private List<Comment> child = new ArrayList<>();
연관관계 설정을 마치고 대댓글 데이터를 json 데이터로 변환하여 작업을 하려고 한다.
결과는 아래와 같다.
StackOverFlowError!
본문 내용을 보면 무한 참조가 발생하여 StackOverFlowError 가 발생 한다.
문제를 살펴보면 응답 Dto를 엔티티 타입으로 받아 이러한 문제가 발생하였다.
Comment 타입에 양방향 관계로 매핑이 되어 있는 데이터까지 Getter() 메서드를 사용하여 직렬화를 하기에 순환 참조가 일어났다.
이러한 문제를 해결하기 위해 많은 방법이 있다.
참조 : https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
참조 : https://k3068.tistory.com/32
아래의 애노테이션을 활용하여 문제 해결
- @JsonManagedReference 참조의 앞쪽 부분으로 정상적으로 직렬화되는 부분이다
- @JsonBackReference 는 참조의 뒷부분이며 직렬화에서 생략
가능하면 Dto를 정의 할 때 엔티티 타입을 선언할 시 순환 참조가 발생할 수 있으니 엔티티 타입으로 받지말고 따로 받을 필드만 정의해서 직렬화하는 것을 권장하고 toString() 정의하고 사용할 때도 순환 참조가 발생할 수 있으니 주의 하자.
'Spring Boot' 카테고리의 다른 글
@Builder 사용시 초기화 필드는 어떻게 될까? (0) | 2022.09.05 |
---|---|
[Spring Boot] Spring 에서 비동기 처리 방식은 어떻게 하고 왜 사용해야 할까? (0) | 2022.07.31 |
[Spring Boot] Interceptor 는 어떻게 사용하고 왜 사용해야 할까? (0) | 2022.07.30 |
[Spring Boot] Filter를 왜 사용해야하고 어떻게 사용하는 걸까? (0) | 2022.07.30 |
[Spring Boot] Validation을 왜 해야하고 어떻게 할까? (0) | 2022.07.29 |
[Spring Boot] 예외처리를 왜 해야하고 어떻게 처리할까? (0) | 2022.07.29 |
ModelMapper (0) | 2022.07.20 |
[Spring Boot] Spring Dependency Injection 동작 원리와 Ioc Container를 알아보자 (0) | 2022.03.02 |