양방향 참조 문제

gminnimk·2024년 10월 28일
0

문제 해결

목록 보기
1/18
post-thumbnail



📢 WasteRecord 와 WasteItem 간의 양방향 참조 문제

오류에 대한 콘솔 내용은

2024-10-27T19:17:39.304+09:00 WARN 24252 --- [ecogrow-backend][nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Ignoring exception, response committed already: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Document nesting depth (1001) exceeds the maximum allowed (1000, from StreamWriteConstraints.getMaxNestingDepth())

2024-10-27T19:17:39.304+09:00 WARN 24252 --- [ecogrow-backend][nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Document nesting depth (1001) exceeds the maximum allowed (1000, from StreamWriteConstraints.getMaxNestingDepth())]

즉 WasteRecord는 다시 WasteItem 리스트를 참조하면서 무한 순환 참조가 발생하여 JSON 직렬화 시 깊이 제한을 초과하는 문제가 발생.

이를 해결하기 위해 양방향 참조 중 하나를 직력화하지 않도록 설정.

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "waste_record_id")
@JsonIgnore
private WasteRecord wasteRecord;

하지만 여전히 문제가 발생.




방법 1) @JsonManagedReference와 @JsonBackReference는 부모-자식 관계에서 순환 참조를 방지하는 데 유용


WasteRecord 클래스에서는 wasteItems 필드에 @JsonManagedReference를 추가, WasteItem 클래스에서는 wasteRecord 필드에 @JsonBackReference를 추가

이렇게 하면 WasteRecord에서 WasteItem 리스트는 직렬화되지만, WasteItem에서 WaseRecord로의 역참조는 무시되어 순환 참조가 발생하지 않게됨.



방법 2) @JsonIgnoreProperties 사용


양방향 참조 필드를 단순히 무시하고 싶은 경우, @JsonIgnoreProperties를 사용하여 참조 필드를 무시.

@JsonIgnoreProperties("wasteRecord")
private List<WasteItem> wasteItems = new ArrayList<>();

정상적으로 결과 도출 확인.




📜근본적인 원인


(1). 엔티티 관계

  • WasteRecord는 WasteItem 과 일대다 관계를 갖고, 이는 각 WasteRecord 가 여러 개의 WasteItem 항목을 가질 수 있음을 의미.

  • WasteItem은 WasteRecord 와 다대일 관계를 가지므로 각 WasteItem 은 자신이 속한 WasteRecord 를 알 수 있음.


(2). 양방향 탐색

  • WasteRecord를 직렬화할 때 직렬 변환기는 wasteItems를 포함한 모든 필드를 포함하게 됨.

  • wasteItems의 각 WasteItem에 대해 직렬 변환기는 WasteRecord를 다시 참조하는 wasteRecord를 포함한 모든 필드를 포함하게 됨.

  • 즉 WasteRecord -> WasteItem -> WasteRecord -> WasteItem -> (무한히 계속).


(3). JSON 직렬화 주기

  • 시리얼라이저가 'WasteRecord'를 발견하면 'WasteItem' 목록을 포함한 모든 필드를 직렬화하려고 시도.

  • 각 WasteItem에는 상위 WasteRecord에 대한 참조가 포함.

  • 직렬 변환기는 이 참조를 다시 WasteItems를 포함하는 WasteRecord로 따라가며 무한 주기를 생성.

  • JSON 직렬화에는 중첨된 개체의 깊이에 제한이 있으므로 '문서 중첩 깊이 초과' 오류가 발생.

  • 주석으로 이 체인을 끊음으로 JSON 직렬화 중 순환 참조를 방지하는 동시에 Java 코드에서 양방향 관계를 그대로 유지


  • @JsonIgnore: WasteRecord가 체인을 WasteItem에 백업하고 루프를 다시 시작하지 않도록 역참조(WasteItem의 WasteRecord)를 무시합니다.

  • @JsonManagedReference 및 @JsonBackReference: 이는 JSON에서 관리되는 부모-자식 관계를 생성하여 "부모" 측(WasteRecord를 WasteItem으로)만 직렬화하고 "하위 항목에서 재귀를 방지합니다. " 측면(WasteItem에서 WasteRecord까지).

0개의 댓글