jOOQ:カスタムタイプの実現方法
もちろん、データベース上ではカスタムタイプを定義しないものとする。可能なDBもあるが、話がややこしくなるのでここでは行わない。
ここで行いたいことは、例えば単純な32ビット整数値(DB上ではINTとかINTEGER)を、Java上ではIntegerとしてアクセスするのではなく、独自の別の型としてアクセスできないかと言うことだ。
問題
例えば、usr_levelという32ビット整数のテーブル列があるとして、Javaプログラム上ではこれを必ずUserLevelというenumで扱うものとした場合、列の出し入れでは32ビット整数ではなく、UserLevelで行えた方が便利だ。つまり、以下のような定義があり、
public enum UserLevel {
NONE, USER, ADMIN, DEVEL;
}
例えば、jOOQの生成するレコード定義のコードとしては、
public TblUserRecord setUsrLevel(Integer value) {
set(3, value);
return this;
}
ではなく、
public TblUserRecord setUsrLevel(UserLevel value) {
set(3, value);
return this;
}
となっていて欲しい。もちろん値の取得の場合も、
public Integer getUsrLevel() {
return (Integer) get(3);
}
ではなく、
public UserLevel getUsrLevel() {
return (UserLevel) get(3);
}
となっていて欲しいのである。
これを行わせる方法がある。
解決方法
以下に解決方法がある。順を追って説明していく
- Custom data type bindings
- Custom data types and type conversion
- Custom data types and type conversion
準備
先に示したUserLevel定義とInteger型との相互変換を行うクラスを定義する。
public class UserLevelConverter implements org.jooq.Converter<Integer, UserLevel> {
@Override
public UserLevel from(Integer databaseObject) {
return UserLevel.values()[databaseObject];
}
@Override
public Integer to(UserLevel userObject) {
return userObject.ordinal();
}
@Override
public Class<Integer> fromType() {
return Integer.class;
}
@Override
public Class<UserLevel> toType() {
return UserLevel.class;
}
}
jOOQの生成定義
これらをコードジェネレーションxmlに設定する。
<database>
<forcedTypes>
<forcedType>
<userType>foo.bar.UserLevel</userType>
<converter>foo.bar.UserLevelConverter</converter>
<includeExpression>USR_LEVEL</includeExpression>
</forcedType>
</forcedTypes>
</database>
includeExpressionには、列名を指定するのだが、例のように列名そのものでもよいし、「TBL_SAMPLE\.USR_LEVEL」のようにテーブル名を指定してもよい。複数ある場合は”|”で区切ればよい。要するにJavaの正規表現が使用できる。
以上でjOOQのコードジェネレーション時に、そもそもデータベース型としては存在しないUserLevelというカスタム型に対応させることができる。