jakarta.servlet.ServletException: Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]
코드 수정 후 통합테스트를 돌려보다가 위와 같은 에러가 발생했다.
좀 더 내려보니 아래와 같이 나와있었다.
Caused by: 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.gdsc.illuwabang.domain.room.Room["user"]->com.gdsc.illuwabang.domain.user.User$HibernateProxy$ap3qTxj3["hibernateLazyInitializer"])
Room 클래스의 user필드가 프록시 객체를 포함해서 직렬화에 실패했다는 에러였다.
문제가 일어난 api는 사용자가 매물 정보를 수정하는 api였다.
수정은 잘 되었으나 repository의 save 메서드가 반환하는 Room을 그대로 response에 담아 반환했는데
이때 문제가 일어난 듯하다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@Column
private String title;
//이하 생략
Room은 User와 연관관계를 가지고 있다.
//RoomService updateRoomInfo 코드 중
return roomRepository.save(newRoom);
save에서 반환된 Room클래스의 객체의 User에는 프록시 객체가 담겨있고
프록시 객체는 직렬화가 될 수 없어 문제가 발생한 것이다.
HTTP 응답 본문에 포함되려면 직렬화가 발생하기 때문에 무조건 문제가 생긴다.
DTO를 통해 해결하는 것이 대표적인 방법이다.
아마 보통은 Response 객체를 쓸텐데 그 안의 클래스 필드를 Dto클래스로 바꾸면 될 듯하다.
부끄럽지만 사실 나는 그러지 않았어서.. Response객체를 만들고 필요한 user이름만 담아서 반환했다.
@Data
@Builder @AllArgsConstructor
public class RoomResponseDto {
private Long id;
private String userName;
private String title;
이외에도
비어있는 객체를 직렬화할 때 실패 시 결과에 포함시키지 않는 방법
=> 근본적인 해결방법이 아니기도 하며 hibernateLazyInitializer라는 필드가 쏙 들어간다고 함
상황에 맞게 강제초기화 할지 혹은 dto를 사용할 지 선택하면 될 듯하다.
강제 초기화는 실제 데이터 로드하기 때문에 쿼리가 늘어나고 성능에 영향을 미칠 수 있다고 한다.
변명 : 스프링부트 잘 모르고 익숙하지 않았고 급하게 진행해서 Room객체를 그대로 반환했음.
일단 끝내고 리팩토링할 때는 커스텀 Response를 만들어서 사용하겠다.
사실이전에 비슷한 문제를 겪은 적이 있다.
해결방법만 찾아 쓰고 유야무야 넘어가서 다시금 문제를 일으킨 것 같다.
lazy 로딩과 프록시 객체 그리고 영속성도 정리하고 공부해 보아야겠다.
스프링부트 공부도 조금씩 다시 해야겠다.