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

+ Recent posts