728x90
Spring/ JPA 에러/ JSON/ REST/ LAZY 로딩 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer
상황
- Springboot로 Restapi를 테스트하는 과정에서 해당 에러가 발생
- 엔티티의 배열을 return 했는데 해당 엔티티가 포함하고 있는 다른 엔티티를 받아오지 못함(LAZY로 설정)
원인
- API에서 Jackson 라이브러리를 사용하여 Serialize할 때 LAZY로딩으로 설정된 다른 엔티티를 Serialize하려고 함
- 해당 엔티티는 비어있는 객체(프록시)이므로 조회할 수 없다
public class Loan {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id")
private Book book;
}
- Loan에 포함된 Book의 FetchType은 LAZY
- Loan 배열을 브라우저로 반환하면 Book은 프록시
해결 방법
1. DTO에 값을 넣어서 반환(저의 해결방법)
- Controller에서 반환할 때 필요한 값을 DTO에 담아서 반환함
- 이렇게 하면 Book을 데이터베이스에서 가져올 수 ㅇ
@AllArgsConstructor
@Data
@NoArgsConstructor
public class LoanDto {
private Long loanId;
private LocalDate loanDate;
private Long bookId;
private Long isbn;
private String title;
private String author;
private String publisher;
}
필요한 데이터를 다 때려 담음 ㅎㅎ
2. hibernamte5: Jackson을 위한 새로운 Hibernate 모듈을 위한 bean 생성
- Hibernamte 객체를 처리할 수 있도록 JSON 직렬화를 사용자가 정의
- ObjectMapper 객체에서 사용할 수 있는 Hibernate용 특정 모듈 jackson-datatype-hibernamte를 제공한다고 한다
- hibernate5를 bean으로 생성하면 Jackson Serialize 시 LAZY 로딩이 설정 된 엔티티를 스킵하여 NULL로 생성한다
- 오류가 안나는 대신 값은 빈 채로 나가는거임
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
build gradle 설정
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
// 빈생성
@Bean
Hibernate5Module hibernate5Module(){
return new Hibernate5Module();
}
// Hibernate5Module.Feature.FORCE_LAZY_LOADING을 true로 변경
// 강제로 LAZY 로딩 설정된 데이터를 가져옴
// 성능문제 + 엔티티 노출 문제
@Bean
Hibernate5Module hibernate5Module(){
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true);
return hibernate5Module;
}
// 이게 맞다
@Bean
Hibernate5Module hibernate5Module(){
Hibernate5Module hibernate5Module = new Hibernate5Module();
return hibernate5Module;
}
}
MyApplication bean생성
Hibernate5Module.Feature.FORCE_LAZY_LOADING을 true로 하지 않고 LAZY를 강제 초기화 하는 게 더 좋은 방법이다
즉 Loan 객체를 불러올 때 Book 객체 데이터를 사용하여 데이터베이스에서 select 해오는거
3. yml파일 spring.jackson.serialization.fail-on-empty-beans 값 false
- 비어있는 객체를 Serialize 할 때 실패 시 결과에 포함하지 않는 방법
- 대신 원하는 값은 못 가져온다
4. 오류가 나는 컬럼에 @JsonIgnore 설정
public class Loan {
...
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id")
private Book book;
}
5. LAZY를 EAGER로 변경
- N+1 문제 발생가능
- 추천 x
참고:
https://offetuoso.github.io/blog/develop/troubleshooting/jpa/no-serializer-found-for-class/
728x90
'Backend > Spring' 카테고리의 다른 글
블로그 만들기 강의: json데이터로 통신 (0) | 2023.02.25 |
---|---|
블로그 만들기 강의: update delete test컨트롤러 (0) | 2023.02.25 |
블로그 만들기 강의: select test컨트롤러 (0) | 2023.02.22 |
Download pre-built shared indexes for JDK and Maven libraries (2) | 2023.02.21 |
Spring Security 3 - @Secured, @PreAuthorize (0) | 2023.02.15 |