본문 바로가기

프로젝트

코틀린 Data Class와 Mybatis 같이 사용할 때 주의점

Mybatis 기본 생성자가 없는 경우

Mybatis에서는 기본 생성자가 없는 경우 Mapper에 정의된 규칙을 사용하지 않는다. 주 생성자의 파라미터와 조회해 온 데이터를 순서대로 매핑을 한다. DefaultResultSetHandler 클래스에서 createResultObject를 통해서 확인을 할 수 있다.

hasDefaultConstructor 메서드는 파라미터 개수가 0인 생성자 여부를 알려주며, 이것이 충족하지 않을 때 Mybatis에서 정한 규칙에 따라 자동으로 객체와 데이터를 매핑을 해준다.  

 

✅ DefaultResultSetHandler.java

 

private Object createResultObject(...){
  if (hasTypeHandlerForResultObject(rsw, resultType)) {} 
  else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
    return objectFactory.create(resultType);
   } else if (shouldApplyAutomaticMappings(resultMap, false)) {
    return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
   }
}

Data Class를 사용할 때 주의점

코틀린의 Data Class의 경우 별도로 생성자를 정의하지 않으면, 전체 멤버 변수를 담고 있는 주 생성자를 하나 생성한다. 이렇게 되면 기본 생성자를 만들어지지 않는다. 이는 조회해 온 데이터의 컬럼 순서대로 매핑이 된다는 것을 의미한다. 이것을 간과하고 사용을 한다면, 매핑 과정에서 데이터 타입이 안 맞는 등의 예외가 발생할 수 있다.

 

✅ 예외를 방어하며 사용하기

 

1. Data Class의 변수에 기본 값을 설정을 해주는 방법이 있다. 이렇게 하면 기본 생성자가 만들어지기 때문이다.

 

data class User(val name: String = "홍길동", val age: Int = 0)

 

2. MyBatis 3.4.3+ 부터 @ConstructorProperties 어노테이션을 사용하면 기본 값 없이도 원하는 규칙에 따라 생성을 할 수 있다.

 

import java.beans.ConstructorProperties

data class User @ConstructorProperties("name", "age") constructor(
    val name: String,
    val age: Int
)

배우고 좋았던 점

회사에서 최근 코틀린 코드를 작성할 일이 많아지면서 기존에 사용하고 있던 Mybatis를 쓸 때 위와 같은 것을 간과해서 문제가 발생했다. 처음에는 그냥 문제만 해결하고 가려고 했는데, 하는 김에 원인 파악을 같이 하면 이후에 도움이 될 것 같았다. 시간은 더 걸렸지만 이를 통해 부족했던 코틀린 Data Class의 지식도 같이 얻을 수 있어서 좋았다.