JSON 직렬화 순환 참조

김형준 Kim Hyeong Jun·2022년 12월 13일
0
post-custom-banner

순환 참조 ???

JPA 에서 양방향으로 연결된 엔티티를 JSON 형태로 직렬화 하는 과정에서,
서로의 정보를 계속 순환하며 참조하여 StackOverFlowError를 발생시키는 현상을 말한다.

직렬화 ???

객체/데이터를 바이트 형태로 변환하여 네트워크를 통해 송수신할 수 있도록 만드는 것을 말한다.


문제 상황

아래 코드를 보면 PostResponseDto 에서 comments 를 생성자를 통해 초기화할 때,List<Comment>를 넣어준다.

코드 자체는 문제가 없다고 생각을 했는데,
막상 실행을 해보니 StackOverFlowError...
처음보는 에러에 당황을 했다.

어디선가 Dto 를 생성하는 방법을 이용해서 진행했다고 했는데,
괜한 오기로

  • 내가 연관관계 잘 못 맺은거 아니야?
  • 이렇게 풀어낼 수 있는 방법이 있을거야...

라며 헤딩 -> 실패 -> 해딩 -> 실패...

-> PostResponseDto

-> Post Entity

-> Comment Entity

그림을 통해보면 이와 같다.


원인

Comment 엔티티를 JSON 형태로 직렬화 하는 과정에서, Comment 엔티티가 참조하고 있는 post엔티티를 조회하게 된다.
또, post엔티티를 조회하는 과정에서, 참조하고 있는 Comment엔티티를 조회한다.

위 과정이 끊임없이 반복되며 StackOverFlowError 발생


해결

일반적으로 DTO를 방식을 사용한다고 하더라...
내가 하기 싫었던게 일반적인 방법...

틀에 박히지 말고 유연하게 생각하자는 생각이 들었다.
어떻게 해서든 문제를 다양한 방법으로 고민하는 것은 좋지만,
이거는 절대 안써라고 하는 발상은 나에게 조금 위험하지 않을까...?

객체 직렬화

Object 를 JSON 형태로 직렬화하기 위해 HttpMessageConverters 에서 jackson Library 활용

jackson의 직렬화 방식
기본적으로 public 필드만 직렬화를 시도
private 필드를 직렬화하기 위해 getter 선언
아래 Exception 이 발생한다면 getter 선언이 되어있는지 확인해 보자.

No serializer found for class
no properties discovered to create BeanSerializer

1. Entity 대신 DTO를 반환

  • 일반적인 방식이라고 한다.
  • Entity 클래스는 데이터베이스와 맞닿는 핵심 클래스이다. 해당 클래스를 기준으로 수많은 클래스나 비즈니스 로직들이 동작하고 있다.
  • Entity 클래스를 통해 여러 클래스들이 영향을 받을 수 있으므로 Entity 클래스를 Request/Response 클래스로 사용하는 것은 추천하지 않는다.
  • 객체지향 설계에서 역할과 책임은 중요한 요소이다.

2. @JsonManagedReference & @JsonBackReference

  • @JsonManagedReference
    -> 연관관계 주인 반대 Entity에 선언
    -> 정상적으로 직렬화 수행

  • @JsonBackReference
    -> 연관관계 주인 Entity에 선언
    -> 직렬화를 하지 않음

3. @JsonIgnore

  • 양방향 연관관계를 가지고 있는 두 엔티티 중 하나의 엔티티의 참조 필드에 직렬화를 제외시키는 방법
  • JSON 직렬화 과정에서 해당 어노테이션이 선언된 필드는 직렬화 대상에서 제외
  • 해당 필드가 직렬화에 필요할 경우에는 적합하지 않은 방법

Reference

https://data-make.tistory.com/727

https://go-coding.tistory.com/101

https://dev-coco.tistory.com/133

profile
I want be a developer🙂
post-custom-banner

0개의 댓글