EFUB 백엔드 세션 7주차 과제

xyzw·2023년 5월 12일
0

Spring

목록 보기
6/22

InvalidDefinitionException 발생

  • 댓글 수정 기능을 구현하고 Postman으로 실행했는데, 에러가 발생하였다.

  • 에러 로그를 확인해보니,
    CommentResponseDto.java의 writer를 처리하는 데에서 InvalidDefinitionException이 발생한 것 같다.

Hibernate: select comment0_.comment_id as comment_1_1_0_, comment0_.created_date 
as created_2_1_0_, comment0_.modified_date as modified3_1_0_, comment0_.content 
as content4_1_0_, comment0_.post_id as post_id5_1_0_, comment0_.member_id 
as member_i6_1_0_ from comment comment0_ where comment0_.comment_id=?
Hibernate: select member0_.member_id as member_i1_2_0_, member0_.created_date 
as created_2_2_0_, member0_.modified_date as modified3_2_0_, member0_.email 
as email4_2_0_, member0_.nickname as nickname5_2_0_, member0_.password 
as password6_2_0_, member0_.status as status7_2_0_, member0_.student_id 
as student_8_2_0_, member0_.university as universi9_2_0_ from member member0_ where member0_.member_id=?
2023-05-12 12:29:58.435 ERROR 16316 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    
: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception 
[Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: 
[simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; 
nested exception is 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: 
efub.assignment.community.comment.dto.CommentResponseDto["writer"]->efub.assignment.community.member.domain.Member$HibernateProxy$izxR8h7v["hibernateLazyInitializer"])] with root cause


  • CommentResponseDto.java 코드
package efub.assignment.community.comment.dto;

import efub.assignment.community.comment.domain.Comment;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class CommentResponseDto {
    private Long commentId;
    private String content;
    private Member writer;
    private Long postId;
    private LocalDateTime createDate;
    private LocalDateTime modifiedDate;

    public CommentResponseDto(Comment comment){
        this.commentId = comment.getCommentId();
        this.content = comment.getContent();
        this.writer = comment.getWriter();
        this.postId = comment.getPost().getPostId();
        this.createDate = comment.getCreatedDate();
        this.modifiedDate = comment.getModifiedDate();
    }
}

원인

Comment 도메인 클래스에 @ManyToOne(fetch = FetchType.LAZY)를 사용하여 Member를 레이지 로딩하도록 설정하였는데, 이는 Hibernate 프록시 객체를 생성하며 필요한 시점에만 실제 객체가 데이터베이스에서 로드되는 방식이다.

프록시 객체는 실제 엔티티 데이터와 함께 추가적인 정보를 가지고 있는데,
이를 JSON으로 직렬화하려고 했을 때, Jackson이 해당 정보를 어떻게 처리해야 할지 모르기 때문에 InvalidDefinitionException이 발생하였다.

📌
직렬화: 객체를 전송가능한 형태로 바꾸는 것
역직렬화: 그 데이터들을 다시 자바 객체로 변환해주는 것


  • Comment.java 코드
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comment extends BaseTimeEntity {
	...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id", nullable = false)
    private Member writer;
	...
}

해결

1. Comment.java 수정하는 방법

Lazy 로딩을 즉시 로딩(EAGER)으로 변경: 명시하지 않으면 즉시 로딩이 디폴트이다.

public class Comment extends BaseTimeEntity {
	...
    @ManyToOne
    @JoinColumn(name = "member_id", nullable = false)
    private Member writer;
	...
}

하지만 실제로는 가급적 Lazy 로딩을 사용하는 것이 좋아, 이 방법은 추천하지 않는다.

2. CommentResponseDto.java 수정하는 방법

private Member writer; -> private String writerName; 변경
: @ManyToOne으로 연결된 객체를 필드로 두지 않는 것

public class CommentResponseDto {
    private Long commentId;
    private String content;
    private String writerName;
    private Long postId;
    private LocalDateTime createDate;
    private LocalDateTime modifiedDate;

    public CommentResponseDto(Comment comment){
        this.commentId = comment.getCommentId();
        this.content = comment.getContent();
        this.writerName = comment.getWriter().getNickname();
        this.postId = comment.getPost().getPostId();
        this.createDate = comment.getCreatedDate();
        this.modifiedDate = comment.getModifiedDate();
    }
}

0개의 댓글