Spring Boot DevTools + Doma2の場合のDomaConfig
Spring Boot 1.3で追加されたDevToolsを使うと、hot deploy(アプリを起動した状態でソースの修正を反映させる)が出来るようになります
DevToolsのhot deployは100%成功はしないのですが、有効にしておくと便利です
ですが、Doma2を組み合わせて使う場合は設定をカスタマイズしておかないとクラスローダーの問題でハマる事になります
DevToolsのhot deployのしくみ
DevToolsはクラスローダーを2つ用意します
- 開発しているアプリケーションのclassをロードするクラスローダー
- 依存ライブラリ(jarファイル)のclassをロードするクラスローダー
ソースが修正されたらアプリケーションのclassをロードするクラスローダーだけを破棄して作り直す事でhot deployを実現しています
(依存ライブラリはアプリ起動中に変更が入らないので作り直し不要)
Doma2を組み合わせて使う場合に何が問題になるのか?
Doma2ではSQLの中でclass/enumを参照出来る機能があります
例えば、この様にRepository(Dao)メソッドの引数にenumを渡して、SQLファイル内で比較が出来て便利です
- enum
1 2 3 4 5 | |
- Repository(Dao)
1 2 3 4 5 6 | |
- SQLファイル
1 2 3 4 5 6 7 8 | |
ですが、Repositoryの引数で渡したenumとSQLファイル内で参照しているenumが別のクラスローダーでロードされるため、Enum#compareToでClassCastExceptionが発生します
[DOMA2111] SQLの組み立てに失敗しました。([2]行目[45]番目の文字付近)。 原因は次のものです。org.seasar.doma.internal.expr.ExpressionException: [DOMA3008] 式[ code == @com.example.Code@A ]の評価に失敗しました([==]番目の文字付近)。 比較演算子[java.lang.ClassCastException]の実行に失敗しました。 被演算子のクラスがjava.lang.Comparableを実装していないか、2つの被演算子の型が比較不可能なのかもしれません。
具体的には以下のようにロードされます
- Repositoryの引数で渡したenum: DevToolsのRestartClassLoaderでロード
- SQLファイルの中でenum参照しているenum: Launcher$AppClassLoaderでロード
この問題は、以下のようにDoma2の設定をカスタマイズすると解決できます
(Domaがアプリと同じクラスローダーRestartClassLoaderを使うようになります)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
doma-spring-bootを使っている場合は以下のようにしてください
doma-spring-bootのサンプルコードを修正したものをここに置いておきました
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |