JaeWon's Devlog
article thumbnail
반응형

1. 에러 발생 상황

- MyBatis(마이바티스) 를 통해서 DB 에서 데이터를 조회하려는 도중 아래와 같은 에러가 발생.

### Cause: java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4] with root cause java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) ~[na:na] at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) ~[na:na] at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248) ~[na:na] at java.base/java.util.Objects.checkIndex(Objects.java:372) ~[na:na] at java.base/java.util.ArrayList.get(ArrayList.java:459) ~[na:na] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createUsingConstructor(DefaultResultSetHandler.java:709) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createByConstructorSignature(DefaultResultSetHandler.java:694) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:658) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:631) ~[mybatis-3.5.7.jar:3.5.7]

- 에러메시지를 보았을 때에는 무언가 배열과 관련 있는 것처럼 보였지만, 검색을 통해 확인해보았을 때는 Lombok 을 사용하면서 발생한 것이다.

2. 원인

- 간단한 예제로 Lombok 을 사용한 Entity 는 아래와 같다.

@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@ToString
@DynamicInsert
public class Todo {

    @Id
    @GeneratedValue
    @Column(name = "todo_id")
    private Long id;

    private String item;

    private String date;

    private boolean completed;

    private String time;

    private LocalDateTime writeDate;
    private LocalDateTime updateDate;

    @Column(columnDefinition = "varchar(1) default 'Y'")
    private String useYn;
}

- MyBatis 를 통해서 조회하고자 하는 쿼리는 다음과 같다.

@Mapper
@Repository
public interface MybatisTestMapper {

    @Results({
            @Result(property = "completed", column = "COMPLETED"),
            @Result(property = "date", column = "DATE"),
            @Result(property = "time", column = "TIME")
    })
    @Select(
            "SELECT COMPLETED, DATE, TIME, USE_YN FROM TODO"
    )
    List<Todo> testSelect();
}

- 해당 메소드를 호출하게 되면 위와 같은 에러가 발생한다.

- 원인은 @Results 의 ResultMap 의 특성 때문으로, 해당 기능을 사용할 경우 MyBatis 가 미리 해당 인스턴스를 생성한다.

- MyBatis 는 데이터를 아래와 같은 순서로 전달한다.

  1. 기본 생성자를 통해 객체를 생성
  2. 생성된 객체에 Setter 연산자를 사용해 데이터를 변경

- 하지만 위 Entity 에서는 모든 파라미터가 포함된 생성자(@AllArgsConstructor)만 존재만 하고, 기본 생성자를 생성하지 않아 발생한 문제이다.

3. 해결 방법

- 해결방법은 간단하게 기본 생성자를 추가하면 된다.

  • Lombok 어노테이션인 @NoArgsConstructor 를 사용하여 추가
  • 직접 기본 생성자를 추가
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor		//	<- 1. 해당 어노테이션을 추가
@AllArgsConstructor
@ToString
@DynamicInsert
public class Todo {

    @Id
    @GeneratedValue
    @Column(name = "todo_id")
    private Long id;

    private String item;

    private String date;

    private boolean completed;

    private String time;

    private LocalDateTime writeDate;
    private LocalDateTime updateDate;

    @Column(columnDefinition = "varchar(1) default 'Y'")
    private String useYn;
    
    public Todo() {}	//	<- 2. 직접 기본 생성자를 작성
}

참고

- https://lob-dev.tistory.com/35

- https://bbubbush.tistory.com/37

반응형
profile

JaeWon's Devlog

@Wonol

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!