これはなに
- Gradleプロジェクトにおいて、MyBatis Generator用のファイルをプロダクションコードから切り離して管理したい
- GradleのSource Setを定義することで解決します
MyBatis Generator(MBG)ではPluginを実装することで、生成されるModelやClientなどを加工することができます。
これを利用して、例えば以下のようにPluginを実装し、MBGの設定ファイルから読み込むことで、Lombokのアノテーションを付与できます。
package plugin;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import java.util.List;
public class MyPlugin extends PluginAdapter {
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
topLevelClass.addImportedType("lombok.Builder");
topLevelClass.addImportedType("lombok.ToString");
topLevelClass.addImportedType("lombok.EqualsAndHashCode");
topLevelClass.addAnnotation("@Builder");
topLevelClass.addAnnotation("@ToString");
topLevelClass.addAnnotation("@EqualsAndHashCode");
return true;
}
}
<generatorConfiguration>
<context id="dsql" targetRuntime="MyBatis3">
<plugin type="plugin.Plugin" />
...
</context>
</generatorConfiguration>
個人的にLombokの@Builderは便利だと思うので、カスタムPluginを実装してアノテーション付与をしています。
ただ、開発を進める中で、カスタムPluginの配置場所を変えたいと思いました。
プロダクションコードに含めると、いろいろ気になる
何も考えず実装すると、配置場所は次のようになりました。
src/
├─ main/
│ ├─ java/
│ │ └─ ...(本来のプロダクションコードのパッケージ)
│ │ ├─ ...
│ │ └─ mbg/
│ │ └─ MyPlugin.java
│ └─ resources/
│ ├─ ...
│ └─ mbg/
│ └─ generatorConfig.xml
└─ test/
├─ java/
└─ resources/
しかしここで、いろいろ気になってきます。
本来のプロダクションコードから一切使用しないのに同じパッケージにある
MBGの設定ファイルならまだしも、カスタムPluginはプロダクションコードから一切使用しないのに、一緒のパッケージに配置しています。
カスタムPluginをプロダクションコードの一部と捉えるならば、特に問題は無いかもしれません。
ただ、同じパッケージに存在することで、
- 誤ってプロダクションコードから呼び出してしまう (呼び出してどうこうするものではないが、間違えてimportしてから気付いて戻すなど、開発効率を下げうる)
- 使わないのに、IDEのサジェストにちらつく
- 本来のプロダクションコードからは一切使用しないのに一緒に置かれているのが、構成上、気になる
などの問題が生じます。
また、次の問題も生じます。
MBG実行にはプロダクションコードはコンパイル可能な状態でなければならない
DB定義と機能実装を同時に行う場合など、実装最中にMBGを実行したくなった場合、この配置はやや厄介です。
なぜなら、MBG実行のためにはコンパイル済みのカスタムpluginが必要であり、カスタムPluginをコンパイルするためにはsrc/main/java配下全体をコンパイル可能な状態にしなければなりません。
実装中の不完全なコードも、コメントアウトやgit stashなどで一旦退避させてからでないと、実行できません。
サクッと実行したいのに、いちいち退避させるのは面倒だと思います。
MBGのPluginを本来のプロダクションコードから切り離したい
ここからが本題です。
先述の問題が生じる原因は、カスタムPluginが、本来のプロダクションコードと同一パッケージ内に配置されているからです。
そこで、本来のプロダクションコードとは別の場所に配置することで、これら問題の解決を試みます。
Source Setを本来のプロダクションコードとは別にする
Gradleでは、Source Setという単位で、Javaファイルと非Javaファイルの抱き合わせを管理しています。
例えば、基本構成であるsrc/main/javaとsrc/main/resourcesは、これらを一つのSource Setとして管理されています。これをMain Source Setと呼ぶことにします。
Gradleの設定ファイルよりSource Setを追加することで、Main Source Setとは別に、ファイルを管理することができます。
sourceSets {
create("xxx")
}
上記のようにSource Setを追加することで、Gradleは以下を行ってくれます。
-
src/xxx/java,src/xxx/resourcesを、xxxというSource Setのソースと認識 -
xxxImplementation,xxxCompileOnlyなどの依存関係グループを定義
ちなみに、普段、dependenciesに単にImplementationやCompileOnlyと書いて動いているのは、これらがMain Source Setに対応するものと定義されているからです。(プロダクトのmainであるため、先頭にSource Set名を付けないものを当てている)
これを利用し、MBG用のファイルを本来のプロダクションコードとは別で管理するようにしてみます。
MBG用のファイルを再配置していく
まずは、MBG用のSource Setを定義します。
sourceSets {
create("mbg")
}
続いて、カスタムPluginをsrc/mbg/java配下に再配置します。
ついでに、MBG設定ファイルも移しちゃいましょう。
src/
└─ mbg/
├─ java/
│ └─ plugin/
│ └─ MyPlugin.java
└─ resources/
└─ generatorConfig.xml
ここで、再配置後のカスタムPluginファイルを開くと、IDEに怒られてしまいます。
依存関係に、MBGを追加していないからですね。
追加していきます。1
dependencies {
// ...
// MyBatis Generator
add("mbgImplementation", "org.mybatis.generator:mybatis-generator-core:1.4.2")
add("mbgRuntimeOnly", "org.postgresql:postgresql")
}
mbgというSource Setを定義したので、対応して自動定義されるmbgImplementation, mbgRuntimeOnlyに追加することができます。
// IDEでエラーが出る書き方
dependencies {
mbgImplementation("org.mybatis.generator:mybatis-generator-core:1.4.2")
mbgRuntimeOnly("org.postgresql:postgresql")
}
上記のように書くと、IDEでは解決できないため、add(...)で追加します。
実行タスクの修正
最後に、実行タスクを修正します。
※ 以下は Qiita:【MyBatis Generator】GradleでサードパーティPluginやAntタスクを使わず実行 を修正する場合の例。
tasks.register<JavaExec>("mbGenerator") {
dependsOn(tasks.named("mbgClasses"))
classpath(sourceSets.getByName("mbg").runtimeClasspath)
mainClass.set("org.mybatis.generator.api.ShellRunner")
args(
"-configfile", "src/mbg/resources/generatorConfig.xml",
"-overwrite",
"-verbose"
)
}
カスタムPluginをコンパイルしてからMBG本体を実行するので、dependsOn(tasks.named("mbgClasses"))が必要です。
また、classpathは、mbgのruntimeClasspathのみの指定でOKです。
これで完成です。
本来のプロダクションコードから、MBG用のファイルを切り離して管理することができました。
ターミナルより、./gradlew mbGeneratorでいつでもMBGを実行することができます。
-
多くの場合、追記しただけではIDEエラーは消えないと思います。IDEでGradleプロジェクトを再読み込みさせる必要があります。 ↩
