섭섭한 개발일지

[SpringBoot RestAPI] 반환 객체 proxy 에러 hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor 본문

프로그래밍/Spring

[SpringBoot RestAPI] 반환 객체 proxy 에러 hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor

Seop 2024. 3. 1. 03:53

Response 시 무한참조로 인한 JSON infinity exception

 

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)]

 

프로젝트 중에 위와 같은 에러를 마주쳤다.

에러는 문의사항 1개의 정보를 가져오는 부분에서 에러가 발생을 했고 에러 내용은 무한한 json을 만드는 것으로 확인된다.

찾은 이유는 아래의 코드에서 발생한 문제로 확인된다.

@Entity
public class Member extends BaseEntity {
    @Comment("회원의 문의 내역")
    @OneToMany(mappedBy = "member")
    @Builder.Default
    private List<Question> questions = new ArrayList<>();
}

@Entity
public class Question extends BaseEntity {
    @Comment("문의사항 작성자")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
    private Member member;

    public void addMember(Member member) {
        this.member = member;
        member.getQuestions().add(this);
    }
}

Entity를 보기 편하게 문제가 된 부분만 축소시켰다.

 

문제는 여기다 Member와 Question이 Lazy 로딩으로 인해서 서로가 필요에 따라 데이터를 조회하게 되는데 이때 무한히 순환이 되면서 JSON Infinite가 발생하는 것이다.

 

문제를 해결하기 위해 Member에서 Question에 대한 데이터를 가지고 있을 필요는 없을 것 같다고 생각했고 Member에서는 Question에 대한 매핑관계를 해제했다.

 

 

Resolved [org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]]

 

Member와 Question이 순환하며 발생하던 에러가 매핑 관계를 해제하니 변경되었다. 참고 게시글

 

[에러노트] 프록시 객체 일 경우 직렬화를 지원하지 않아 생기는 에러

상품 조회 api 구현 후 테스트 할때 생긴 에러이다. 프록시 객체는 기본적으로 직렬화(Serialization)을 지원하지 않습니다.주어진 오류 내용에서 알 수 있는 것은 Jackson 라이브러리가 org.hibernate.proxy.

velog.io

 

이 에러는 response dto에서 entity의 프록시 객체를 사용하기에 발생하는 오류로 확인이 된다.

 

현재 response dto를 확인해보면

public class QuestionResponse {
    @Schema(description = "문의사항 고유 식별 번호")
    private Long id;

    @Schema(description = "문의사항 작성자")
    private Member member;

    @Schema(description = "문의사항 제목")
    private String title;

    @Schema(description = "문의사항 내용")
    private String content;

    @Schema(description = "문의사항 등록 이미지")
    private NcpFileResponse file;

     @Schema(description = "문의사항에 등록된 답변")
     private List<AnswerResponse> answers;
}

위와 같이 되어 있고

Member 가 response 가 아닌 실제 엔티티 클래스로 타입이 잡혀있다.

 

이 오류의 주된 문제는 Jackson 라이브러리가 클래스에 대한 직렬화 기능을 찾지 못했다는 것이다.

이 문제는 하이버네이트의 프록시 객체때문인데 지연로딩을 하기위해서는 프록시 객체를 사용하므로 Question에 있는 Member 가 문제가 된 것이다.

 

그럼 문제가 있는지 확인하기 위해

우선 QuestionResponse 에서 Member를 Response 형태로 변경을 해보겠다.

public class QuestionResponse {
		...

    @Schema(description = "문의사항 작성자")
    private MemberResponse member;

		...
}

postman 으로 조회가 가능해졌다.

 

Response를 통해서 문제가 처리된 걸 생각해서

첫번째 순환참조가 되며 무한히 만들어지던 문제는 다시 원본 코드로 복구를 해도 될 것 같다

 

 

복구를 해도 정상적으로 데이터가 조회가 되며

결과적으로 문제는 rest 통신간에 java 데이터를 json으로 변환하는 하는 과정에서 프록시 객체의 문제점으로 파악이 된다 !

 

끝 !

Comments