쌓고 쌓다
양방향 연관관계 매핑 JSON 순환참조 문제 본문
에러 발생
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: Infinite recursion (StackOverflowError)]
java.lang.StackOverflowError
보면 jackson 라이브러리에서 무한하게 에러 메시지를 보내면서 StackOverflow에러가 발생했다.
에러 원인
Poster
@Entity
@Getter
@Setter
public class Poster {
@OneToMany(mappedBy = "poster", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<UploadFile> imgFiles = new ArrayList<>();
}
UploadFile
@Entity
@NoArgsConstructor
@Getter
@Setter
public class UploadFile {
@ManyToOne
@JoinColumn(name="pno")
private Poster poster;
}
보면 Poster과 UploadFile은 양방향 매핑이 되어있다.
즉, 순환 참조가 되어있다.
Poster은 UploadFile을 참조하고 있고 UploadFile은 Poster를 참조하고 있다.
Jackson이 엔티티를 JSON으로 변환(Getter를 사용하여)하는 과정에서 문제가 발생한다.
Poster를 JSON으로 변환하는 과정에서
UploadFile이 존재하여 UploadFile을 직렬화를 먼저하고자 합니다.
UploadFile에는 또 Poster가 있기에 Poster를 직렬화하고자 합니다.
이렇게 무한루프에 빠지게 됩니다.
(직렬화: 객체->JSON, 비직렬화: JSON -> 객체)
해결 방법
1. @JsonIgnore
@Entity
@Getter
@Setter
public class Poster {
@OneToMany(mappedBy = "poster", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
@JsonIgnore
private List<UploadFile> imgFiles = new ArrayList<>();
}
JSON으로 변환할때 이 필드는 직렬화에서 무시합니다.
2. @JsonManagedReference, @JsonBackReference
@JsonManagedReference를 직렬화를 수행할 곳에 (또는 연관관계 주인 반대 Entity)
@JsonBackReference는 직렬화하지 않을 곳에 추가한다. (또는 연관관계 주인 Entity)
아래의 예에서는 연관관계의 주인을 따지지 않고 원하는 직렬화 구간에 적용하였다.
원래 연관관계의 주인을 따져서 바람직하게 작성하는것이 옳다.
public class Poster {
@JsonBackReference
@OneToMany(mappedBy = "poster", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<UploadFile> imgFiles = new ArrayList<>();
}
public class UploadFile {
@JsonManagedReference
@ManyToOne
@JoinColumn(name="pno")
private Poster poster;
}
Poster의 imgFiles는 @JsonBackReference로 직렬화를 수행하지 않고
UploadFile의 poster는 직렬화 대상이 된다.
Poster 응답
UploadFile 응답
3. DTO
그럼 양방향으로 조회하고싶을때 어떻게 방법이 없는걸까?
데이터 전송을 위한 오브젝트(data transfer object)인 DTO를 따로 만들어 필요한 데이터만 담아 응답하는 방법도 있다.
+ @JsonManagedReference, @JsonBackReference를 연관관계 주인에 맞춰 올바르게 사용하자.
안그럼 나중에 문제가된다..
https://non-stop.tistory.com/614
'프로그래밍 > JPA' 카테고리의 다른 글
JPA find 후 엔티티 변경시 UPDATE가 안날라갈때 with Transaction (0) | 2023.11.10 |
---|---|
JPA에서 save시 SELECT 쿼리 실행 (1) | 2023.09.11 |
[JPA] 고아 객체 제거 + orphanRemoval 동작하지 않을때 (0) | 2023.08.18 |
[JPA] 영속성 전이(CASCADE): 삭제 (0) | 2023.08.18 |
[JPA] 영속성 전이(CASCADE): 저장 (0) | 2023.08.17 |