JPA JsonMappingException: Infinite recursion (StackOverflowError) - 무한루프
JPA를 사용해 개발을 하던 도중 낯선 에러를 보게 되었습니다.
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain:
JsonMapping 을 하던 도중 무한 순환을 하여 StackOverflow 에러가 났다는 에러였습니다.
뭔가 하고 찾고 분석한 결과 원인을 알아내고 수정할 수 있었습니다.
문제의 컨트롤러에서 아래와 같이 ResponseEntity 를 리턴타입으로 가지고 있었습니다.
public ResponseEntity<?> searchOrders() {
return ResponseEntity.ok(new ApiResponse(123, "Success", entityObject));
Http Response body 에 object 를 serialized 할 때 jackson 을 사용하는데 jackson 이 데이터를 뽑을 때 getter 기준으로 뽑아낸다고 합니다.
그런데 제가 한 실수가 일단 성공하고 return 이 잘되는지 확인을 먼저 하려는 마음에 사용하던 Entity 객체를 return 하였는데
이 Entity가 OneToMany 로 자식 엔티티를 참조하고 자식 Entity는 ManyToOne 으로 부모 Entity를 참조하고 있는 상태였습니다.
@Entity
@Table(name = "test")
public class Test {
...
@OneToMany(mappedBy = "test")
private List<SubTest> subTests = new ArrayList<>();
}
@Entity
@Table(name = "biz_order_products")
public class BizOrderProduct {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "testId")
private Test test;
}
그래서 양방향 참조를 하는 관계에서 getter 를 하게 되니 서로 참조하고 있고 get 을 하면 순환을 하여 무한루프에 빠지게 되고 이 데이터가 메모리의 Stack 영역에 계속해서 쌓이게 되어 메모리의 Heap 영역을 침범하게 되는 StackOverflow 에러가 발생하게 된 것 이였습니다.
이를 해결하기 위해선
1. 새로운 객체를 만들어 이를 return.
2. @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "순환이 일어나는 참조객체에 맵핑되는 컬럼") 으로 순환을 끊기.
3. 양방향 참조를 단방향 참조로 만들기.
4. fetch join을 사용하기.
가 있습니다.
해결 방법이 더 있을 수 있다면 댓글로 알려주시면 감사하겠습니다.
'Database > JPA & JPQL' 카테고리의 다른 글
[JPA] Id Annotation과 return cached data (0) | 2018.07.05 |
---|---|
Pageable로 Limit 걸기 (0) | 2018.06.23 |
JPQL이란? (0) | 2018.06.18 |