JPA Lazy 로딩 JSON Serialize 에러

Haechan Kim·2024년 2월 16일
0

Spring

목록 보기
57/68
post-custom-banner

No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer

1:N 연관관계에서 지연 로딩(lazy)을 사용하는 경우 발생할 수 있는 에러.

지연 로딩의 경우 필요한 시점에 데아터를 불러 온다.
그 전까지는 proxy 객체가 들어있는데 -> proxy를 serialize(직렬화)할 수 없기 때문에 발생하는 에러!

// settlement와 contract는 1:N 관계
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Settlement {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 계약서
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "contractId")
    private Contract contract;
    
    ...
}


// 서비스 코드
public List<SettlementDto> test(Long type, Long id, LocalDate date) {
	List<Settlement> settlementList = settlementRepository.test(type, id, date);

	List<SettlementDto> settlementDtoList = settlementList.stream()
			.map(SettlementDto::of)
			.toList();

	return settlementDtoList;
}

이런식으로 바로 호출하게 되면 에러 발생.
settlementDto 객체에 들어있는 Contract는 proxy인 상태.

해결 방법

dto를 만들어 초기화를 하자.

SettlementDto를 이런식으로 작성해서 Contract에서 필요한 요소만 추출하자.

@Getter
@Setter
@ToString
@NoArgsConstructor
public class SettlementDto {

	// Contract가 아닌 ContractDto을 새로 만들기 
    private ContractDto contractDto;
    private Long type;
    private Long memberId;
    private LocalDateTime settleDate;
    private Double fee;

    @Builder
    public SettlementDto(ContractDto contractDto, Long type, Long memberId, LocalDateTime settleDate, Double fee) {
        this.contractDto = contractDto;
        this.type = type;
        this.memberId = memberId;
        this.settleDate = settleDate;
        this.fee = fee;
    }

    public static SettlementDto of (Settlement settlement) {

        ContractDto contractDto = ContractDto.of(settlement.getContract());

        return SettlementDto.builder()
                .contractDto(contractDto)
                .type(settlement.getType())
                .memberId(settlement.getMemberId())
                .settleDate(settlement.getSettleDate())
                .fee(settlement.getFee())
                .build();
    }
}
post-custom-banner

0개의 댓글