ページ

2018-10-04

Spring Data JDBC で Enum を序数でない数値に変換する

Spring Data JDBC では、デフォルトではenumはnameに変換される。しかし、DBに格納する際は特定のコード(数値)に変換したいことも多いと思うので、その方法について書く。
Kotlinで書いてしまうが、Javaへの読み替えは難しくないと思う。

インタフェースの作成と利用

enumはordinal(序数)を持っているが、それぞれの項目で固定されたコード(数値)を設定したいので、コードを設定できるinterfaceを作成する。

interface CodedEnum {
    val code: Int
}
enum側で使っておく。
enum class Status(override val code: Int): CodedEnum {
    SUCCESS(1),
    FAILURE(2),
}

NamedParameterJdbcTemplateをカスタマイズしてパラメータを差し替える

Spring Data JDBC は内部でSpring JDBC のNamedParameterJdbcTemplateを使っているが、これが@Query で指定したパラメータの変換を担っている。 パラメータをenumで受け取るには、これがCodedEnumを扱えるようになる必要があるので、カスタマイズされたNamedParameterJdbcTemplateを準備する。
対応してる箇所が低いところすぎて気持ち悪いけど、getPreparedStatementCreator() は protected なので、NamedParameterJdbcTemplate的にはここを置き換えることは想定されているんだろうなと思いつつ対応。 enumに限らずここを書き換えたい作業はあると思うので、将来的にはSpring Data JDBC がもっと便利になって、こういう処理はいらなくなるかも。

Converterの追加とCustomizedNamedParameterJdbcTemplateの適用

@EnableJdbcRepositories の @Configuration で、まずnamedParameterJdbcTemplateを差し替える。

そして、値の変換を行うJdbcCustomConversionsにもEnumの変換処理を入れる。基本的には、write方面はinterfaceをそのまま.codeで変換して、readは型がわからないのでfactoryを利用して変換する。 ここでポイントになるのは、Spring Data JDBC の BasicRelationalPersistentPropertyがDB向け変換を行う際にEnumをStringに変換するということ。 これに対応するため、to Stringの変換を用意しておく。

 これで、codeで設定した値が利用されるようになる。