Backend/Spring Project

[Spring Framework/스프링 프레임워크] DTO, VO에 @Builder 패턴 적용 시 Mybatis 에러 해결방법 (빌더패턴, 쿼리) java.lang.IndexOutOfBoundsException:

냠냠:) 2021. 4. 10. 22:32

문제

요즘 스프링을 사용해서 개인 프로젝트를 진행하는데, 실제로 Builder 패턴을 사용하지 않아도 가독성이 좋을 만큼 짧은 코드를 Builder패턴에 익숙해지고자 DTO에 Builder 패턴을 적용해봤다.

 

적용을 하고 잘 동작하나 게시판에 들어갔는데, 댓글 리스트를 조회해오는 기능이 제대로 동작하지 않고 에러를 뱉는 상황이었다. 

 

 

문제 접근

바꾼 코드에 문제가 있을 것이라고 예상했다. 실제로 에러는 Mybatis에서 조회해온 결과를 확인하는 로직에서 발생했다.

에러 로그

문제 분석

 

-ReplyDTO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
 
@Setter
@Getter
@ToString
@Builder //추가된 부분
public class ReplyDTO {
 
    private String replyId;
    private String boardId;
    private String parentRplId;
    private String writerId;
    private String writerName;
    private String content;
    private String likeCount;
    private String createBy;
    private String createTime;
    private String useYn;
                                                                                  
}
cs

 

-ReplyMapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <!-- 댓글 리스트 조회 (첫 페이지 로딩 용) -->
    <select id="selectReplyList" resultType="ReplyDTO">
    /* 2021.03.14 selectReplyList */
        SELECT  reply_id
               ,board_id
               ,parent_rpl_id
               ,writer_id
               ,like_count
               ,content
               ,create_by
               ,DATE_FORMAT(create_time, '%Y-%m-%d %H:%i') AS create_time                      
          FROM reply
         WHERE board_id = #{boardId} AND use_yn = 1
    </select>
cs

Controller에서 ReplyDTO에 Builder 값을 넣었을 땐 이상이 없었는데, Mybatis에서는 위와 같은 ReplyDTO에는 값을 못 넣어주는 것으로 확인했다.

 

 

해결 방법

구글의 힘을 빌려 문제를 해결했다.

 

실제 MyBatis에서는 DTO 객체에 값을 넣어줄 땐 기본 생성자로 객체를 생성한 뒤, Setter 메서드를 이용해서 값을 넣어준다고 한다. 

 

하지만 @Builder 어노테이션이 Builder 패턴을 위한 생성자만 정의하기 때문에, 기본 생성자는 없는 상태였고, Builder패턴을 위한 생성자만 있는 상태여서 에러가 났던 것이다. (자바는 생성자가 없을 경우 기본 생성자를 자동으로 만듦, 있는 경우 만들지 않음)

 

 

해결된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
 
@Setter
@Getter
@ToString
@NoArgsConstructor
public class ReplyDTO {
 
    private String replyId;
    private String boardId;
    private String parentRplId;
    private String writerId;
    private String writerName;
    private String content;
    private String likeCount;
    private String createBy;
    private String createTime;
    private String useYn;
 
    @Builder
    public ReplyDTO(String replyId, String boardId, String parentRplId, String writerId, String writerName,
            String content, String likeCount, String createBy, String createTime, String useYn) {
        super();
        this.replyId = replyId;
        this.boardId = boardId;
        this.parentRplId = parentRplId;
        this.writerId = writerId;
        this.writerName = writerName;
        this.content = content;
        this.likeCount = likeCount;
        this.createBy = createBy;
        this.createTime = createTime;
        this.useYn = useYn;
    }
 
 
}
cs

 

- @NoArgsConstructor : 기본 생성자 생성 어노테이션

 

위와 같이 @NoArgsConstructor 어노테이션을 사용하여 기본 생성자를 생성하고, 추가로 빌더 패턴에 해당하는 생성자를 만들어주어 @Builder 어노테이션을 추가했다.

 

-> 실제 테스트 시 문제없이 원래대로 잘 작동하는 것을 확인할 수 있었다.

 

이 글을 읽으시는 분들이 이 방법으로 문제가 해결이 됐으면 좋겠다.

 

 

 

쉽게 생성자 만드는 방법(은근히 모르시는 분 많으시길래)

 

 

 

 

반응형