Spring 지연로딩(FetchType Lazy) 사용시 조회할 때 Response JSON 변환 과정에서 에러 발생하는 이유

하스레·2022년 12월 4일
1

오류 설명

스프링에서 지연로딩 사용시, api 요청에 대한 응답으로 jackson을 통해 json으로 객체를 변환하는 과정에서 다음과 같은 에러가 발생하는 경우가 다수 있다.

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: java.util.ArrayList[0]->jpabook.jpashop.domain.Order["member"]->jpabook.jpashop.domain.Member$HibernateProxy$fK98U2VJ["hibernateLazyInitializer"])

오류 원인

현재 상황을 설명하자면, Order 클래스 내부에 member 객체를 @ManyToOne으로 설정해놓았는데 이때 FetchType을 Lazy 로 설정해놓았다.

public class Order {
	
    ...

    @ManyToOne(fetch = LAZY)
    private Member member;
}

이렇게 지연로딩을 사용하면, Order 객체를 조회할 때 디비에서 그가 참조하는 member객체는 가져오지 않고 Order만 가져오게 된다. 그러면서 이때 member를 실제 엔티티가 아닌 프록시 객체로 생성해놓는다.

(오류를 잘 보면 ByteBuddyInterceptor를 발견할 수 있는데, 실제로는 다음과 같이 프록시 객체를 생성할 때 사용된다)

public class Order {
	
    ...

    @ManyToOne(fetch = LAZY)
    private Member member = new ByteBuddyInterceptor();
}

그리고 나중에 member를 실제로 손대려고 하면, member객체도 디비에서 가져와 비어있던 프록시 객체에 실제 값을 채우는 프록시 초기화를 하게 된다.
(지연로딩은 영속성 컨텍스트에서 조회한다. 이후 이미 조회된 경우 쿼리 X)

문제는, Jackson 라이브러리가 이 프록시 객체를 json으로 변환하려고 할 때 순수 자바 객체와 달라 어떻게 대처해야할지 모른다는 것이다. 따라서 위와 같은 에러가 발생하게 된다.

오류 해결 방법

  1. Hibernate5Module를 사용하여 초기화된 프록시객체만 노출되게 한다.
  2. DTO를 사용한다.
    => 기본적으로, 엔티티를 외부에 노출해서는 안되므로 그냥 필수적으로 DTO를
    사용하도록 하자.
  3. 예를들어 컨트롤러에서 Lazy 강제 초기화를 해줄수도 있긴하다.
for(Order order: orders) 
	order.getMember().getName();

이렇게 해주면 order.getMember()까진 프록시 객체인데, getName()을 하면 디비에서 가져오게된다.


참고
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-API%EA%B0%9C%EB%B0%9C-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94/dashboard

profile
Software Developer

0개의 댓글