- mysql
- nginx
- 자바
- jpa
- 스프링부트
- java
- @transactional
- string
- session
- Git
- ORM
- AWS
- springboot
- DI
- sql
- spring security 6
- Django
- join
- Docker
- SSL
- 프로그래머스
- PYTHON
- 데이터베이스
- 1차원 배열
- select
- spring boot
- 스프링
- spring mvc
- 문자열
- spring
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
개발하는 자몽
[JPA Error] FetchType.LAZY로 인한 오류 : Type definition error 본문
오류 질문을 받았는데, 내가 지난번에 겪었던 에러와 유사한 것 같아서 정리해두려고 한다.
상황
API에 요청을 하고 해당 정보를 DB에 담는 것까지는 에러 없이 진행이 된다. 하지만 저장한 정보를 조회하면 아래와 같은 에러가 콘솔창에 나타난다. Postman에서는 500 에러라고 알려준다. (오류 전문이 아닌 중요한 부분만 가져왔다)
2023-02-13T09:52:21.966+09:00 ERROR 71150 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.xxx.xxx.domain.dto.Response["xxx"]->com.xxx.xxx.domain.dto.record.XxxResponse["xxx"]->java.util.ArrayList[0]->com.xxx.x.domain.entity.xxx["xxx"]->com.xxx.xxx.domain.entity.Xxx["xxx"]->com.xxx.xxx.domain.entity.Xxx["xxx"]->com.xxx.xxx.domain.entity.Group$HibernateProxy$iFEdWF88["hibernateLazyInitializer"])
아래줄(hibernateLazyInitializer)에서 오류(InvalidDefinitionException)가 발생했다고 알려준다. 잘 보면, 에러와 함께 아래처럼 해서 오류를 피하라고 알려준다.
to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS
에러가 난 코드를 비슷하게 작성해봤다.
@Entity
...
class Xxx {
@Id @generatedvalue(strategy = generationtype.identity)
private Long id;
@ManyToOne(Fetch = fetchType.LAZY)
private type fieldA;
...
}
엔티티의 ManyToOne + 지연 로딩 필드에서 발생했다. (fetchType은 DB에서 엔티티 정보를 조회할 때 연관되어 있는 다른 엔티티의 정보를 어느 시점에 가져올지 정하는 옵션이다)
클라이언트로부터 받은 데이터를 저장하고, 성공적으로 저장이 되면 해당 객체를 반환하도록 했는데 에러가 발생한 것이다. 저장에 성공한 Xxx 객체에 대한 정보를 JSON 타입으로 변환하는 과정에서 Xxx 객체와 매핑되어 있는 fieldA를 serialize(직렬화)할 때 지연 로딩으로 인해 실제 fieldA 객체가 아닌 프록시 객체를 serialize하려고 했기 때문에 이러한 에러가 발행했다. (지연 로딩으로 설정 시 데이터를 요청하면 연관 엔티티는 hibernate가 프록시 객체를 반환한다)
해결
해당 필드에 Jackson 애노테이션인 @JsonIgnore를 적용했다.
오류 본문에 나와있는 hibernateLazyInitializer는 엔티티를 지연 로딩하기 위해 사용된다. DB에 엔티티를 저장할 때 JPA 엔티티는 엔티티의 모든 필드와 hibernateLazyInitializer 필드를 serialize 한다. 이러한 필드를 무시하지 않으면 해당 필드들은 JSON 형태로 serialize 된다. 이렇게 불필요한 serialization을 피하려면 @JsonIgnore를 사용해야 한다. 이는 serialize된 JSON이 hibernateLazyInitializer 필드를 갖지 않으며, 객체에 가지고 있다면 무시하라는 의미이다.
따라서 아래처럼 코드를 작성하면 Xxx를 JSON 형태로 변환할 때 fieldA를 제외한 정보만 serialize 된다.
@Entity
...
class Xxx {
@Id @generatedvalue(strategy = generationtype.identity)
private Long id;
@ManyToOne(Fetch = fetchType.LAZY)
@JsonIgnore
private relatedEntityType fieldA;
...
}
참고
'Java > Spring' 카테고리의 다른 글
[Spring] 쿠키의 보안 문제와 세션 (0) | 2023.03.16 |
---|---|
[Spring] 로그인, 로그아웃 처리 - 쿠키, 세션 (0) | 2023.03.15 |
[JPA Error] save할 때 @ManyToOne 필드가 null인 현상 (0) | 2023.01.07 |
[Thymeleaf + Spring Security] sec:authorize (0) | 2023.01.06 |
[Spring Security] @PreAuthorize (0) | 2023.01.05 |