🌊

Doma CodeGen PluginでJava16のrecord class/Kotlinのdata classのEntityを生成する

2024/03/24に公開

前提

org.domaframework.doma.codegen:2.0.0
Java16以上

テンプレートのカスタム方法

時代はイミュータブル…ということで、Java16のrecord classとKotlinのdata classを使ってEntityを生成するようにしてみました。

テンプレートファイルをカスタムできるらしく、公式ドキュメントでは、以下説明があります。

https://doma.readthedocs.io/ja/latest/codegen/#using-custom-template-files

カスタムテンプレートファイルを作成するには、ファイル名を変更せずにコピーして内容を変更します。 次に、 templateDir オプションに指定されたディレクトリに配置します。

テンプレートファイルのカスタム

build.gradle.ktsのdomaCodeGen -> register -> templateDirにカスタムテンプレートファイルを指定します。

templateDir = file("src/main/resources/doma_codegen_template")

設定例
https://github.com/momosetkn/experimental-doma/blob/de0ee05fef47ef5618d74b612f0894712242bb5d/build.gradle.kts#L242

Java16のrecord classのEntityを生成する

以下の元とするentity.ftlをベースにいじっていきます。
https://github.com/domaframework/doma-codegen-plugin/blob/master/codegen/src/main/resources/org/seasar/doma/gradle/codegen/template/java/entity.ftl

で、完成したテンプレートが以下です。recordクラスは継承ができないため、useMappedSuperclassの設定を無視しています。
https://github.com/momosetkn/experimental-doma/blob/3482436c479ea6e6dccc6bb077a3ef809ac2779e/src/main/resources/doma_codegen_template/java/entity.ftl

Kotlinのdata classのEntityを生成する

以下の元とするentity.ftlをベースにいじっていきます。
https://github.com/domaframework/doma-codegen-plugin/blob/master/codegen/src/main/resources/org/seasar/doma/gradle/codegen/template/kotlin/entity.ftl

https://github.com/domaframework/doma-codegen-plugin/blob/fc026b9b1fba43952f6b498d5eb3962909428fad/codegen/src/main/java/org/seasar/doma/gradle/codegen/desc/KotlinClassResolver.java
https://github.com/domaframework/doma-codegen-plugin/blob/d2b67e04f9b42f4db265105e660211e36970a407/codegen/src/main/java/org/seasar/doma/gradle/codegen/desc/EntityPropertyDescFactory.java#L139
StringやLocalDateTimeがすべてnullable扱いになってしまうようで、その原因がこちらのようで、KotlinClassResolverで未定義はデフォルト値を"null"としていて、デフォルト値が"null"もnullableと判定する挙動と組み合わさって、この挙動になるようです。

そこで、デフォルト値が"null"じゃないLanguageClassResolverをbuild.gradle.kts上で定義し、それを参照するようにして回避しました。
https://github.com/momosetkn/experimental-doma/blob/794422339cea5e5e028f9cdf1d4cb7206bf15c07/build.gradle.kts#L235-L240

で、完成したテンプレートが以下です。data classはJava16のrecordクラスと違って継承はできますが、ぼくの場合は継承を使わないので、useMappedSuperclassの設定を無視しています。
また元のentity.ftlだと、デフォルト値が設定されていましたが、nullableの場合のみnullのデフォルト値を設定するようにしています。
https://github.com/momosetkn/experimental-doma/blob/5f0a8db9b3a25dffac25baa9412412fbd4502f08/src/main/resources/doma_codegen_template/kotlin/entity.ftl

その他設定

デフォルトだと、EntityListener(データベースで言うトリガーみたいな機能)や抽象クラスが使われるらしいですが、不要であれば、以下設定をbuild.gradle.ktsのdomaCodeGen -> register -> entityブロックに付与します。

useListener = false
useMappedSuperclass = false

設定例
https://github.com/momosetkn/experimental-doma/blob/794422339cea5e5e028f9cdf1d4cb7206bf15c07/build.gradle.kts#L254-L255

GitHubで編集を提案

Discussion