댓글 수정 기능을 구현하고 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;
...
}
Comment.java
수정하는 방법Lazy 로딩을 즉시 로딩(EAGER)으로 변경: 명시하지 않으면 즉시 로딩이 디폴트이다.
public class Comment extends BaseTimeEntity {
...
@ManyToOne
@JoinColumn(name = "member_id", nullable = false)
private Member writer;
...
}
하지만 실제로는 가급적 Lazy 로딩을 사용하는 것이 좋아, 이 방법은 추천하지 않는다.
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();
}
}