본문 바로가기
Spring

[Spring] Spring Boot + Kotlin + MyBatis ResultType, ResultClass에 Enum 사용법

by 노력남자 2023. 7. 2.
반응형

이번 포스팅에선 ResultType, ResultClass에 Enum을 사용하는 방법에 대해 알아보겠다.

 

문제

 

아래와 같이 Customer를 ResultType으로 쓰는 쿼리가 있다.

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.spring_kotlin_mybatis.CustomerMapper">

    <resultMap id="customerMap" type="com.example.spring_kotlin_mybatis.Customer">
        <result property="customerName" column="customer_name"/>
        <result property="id" column="id"/>
    </resultMap>

    <select id="findByIdAndName" resultType="com.example.spring_kotlin_mybatis.Customer">
        SELECT customer_name, id
        FROM customer
        <include refid="findByIdAndNameWhere" />
    </select>

    <sql id="findByIdAndNameWhere">
        <where>
            <if test="id != null">
                AND id = #{id}
            </if>
            <if test="name != null">
                AND customer_name = #{name}
            </if>
        </where>
    </sql>
</mapper>

 

Customer 클래스는 아래와 같이 생겼다.

 

Customer 클래스의 type을 보면 CustomerType이다.

 

class Customer(
    val id: Long,
    val customerName: String,
    val type: CustomerType
)

enum class CustomerType(
    val code: String
) {
    GOLD("G"),
    BRONZE("B");
}

 

customer 테이블의 type의 값이 "GOLD", "BRONZE"면 정상적으로 잘 된다.

 

기본적으로 Enum의 name() 값을 사용해서 잘 된다.

 

근데 만약 CustomerType에 code값이 DB에 저장되어 있다면?

 

nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'type' from result set.  Cause: java.lang.IllegalArgumentException: No enum constant com.example.spring_kotlin_mybatis.CustomerType.B

 

위와 같은 에러가 발생한다.

 

해결책

 

enum에 code로 찾을 수 있는 find method를 추가해주자.

 

enum class CustomerType(
    val code: String
) {
    GOLD("G"),
    BRONZE("B");

    companion object {
        fun find(code: String) = CustomerType.values().find { it.code == code }
    }
}

 

이후 type handler를 추가해줘야 한다.

 

package com.example.spring_kotlin_mybatis.typehandler

import com.example.spring_kotlin_mybatis.CustomerType
import org.apache.ibatis.type.BaseTypeHandler
import org.apache.ibatis.type.JdbcType
import java.sql.CallableStatement
import java.sql.PreparedStatement
import java.sql.ResultSet

class CustomerTypeHandler : BaseTypeHandler<CustomerType>() {

    override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: CustomerType, jdbcType: JdbcType) {
        ps.setString(i, parameter.code)
    }

    override fun getNullableResult(rs: ResultSet, columnName: String): CustomerType? {
        return CustomerType.find(rs.getString(columnName))
    }

    override fun getNullableResult(rs: ResultSet, columnIndex: Int): CustomerType? {
        return CustomerType.find(rs.getString(columnIndex))
    }

    override fun getNullableResult(cs: CallableStatement, columnIndex: Int): CustomerType? {
        return CustomerType.find(cs.getString(columnIndex))
    }
}

 

위 type handler 패키지는 "com.example.spring_kotlin_mybatis.typehandler"다

 

아래와 같이 설정하자.

 

// application.yml
mybatis:
  type-handlers-package: com.example.spring_kotlin_mybatis.typehandler
  
// sqlSessionFactory Bean을 별도 설정한 경우
SqlSessionFactoryBean().setTypeHandlersPackage("com.example.spring_kotlin_mybatis.typehandler")

 

끝!

반응형

댓글