Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Doma入門 - 注釈処理

はじめに

Domaの一番の特徴であり、鬼門でもあるのが注釈処理(アノテーションプロセッシング)です。

最新のDoma 2.44.1を前提に記述しますが、基本的にはどのバージョンにも当てはまる内容となっています。

Domaの他の機能紹介についてはDoma入門もお読みください。

注釈処理とは

注釈処理を使うと、コンパイル時にソースコードに付与されたアノテーションを読み取って、別のソースコードやバイトコードを生成できます。

Domaはソースコードを生成するタイプのフレームワークですが、例えばMicronautはバイトコードを生成しています。

利用者視点で見ると、ソースコードを生成するタイプはコードを読んだりブレイクポイントを置いたりできるのでデバッグしやすく、バイトコードを生成するタイプはコンパイル時間をスキップできるという特長があります。

注釈処理の利点

利点を大別すると3つあるのではと思います。

  1. ボイラープレートコードを削減できる
  2. コンパイル時にエラーを検出できる
  3. 実行時のブートストラップ(初期化)を高速化できる

ボイラープレートコードを削減できる

ボイラープレートコード削減は注釈処理に限った利点ではなく、例えばリフレクションなどでも実現できます。この点に関しては、AutoValueというプロダクトが、注釈処理と他の手法を比較していて参考になります。特にこのスライドが面白いです。

AutoValueのスライドでは触れられていませんが、リフレクションに限って言えば、ネイティブイメージ化を考慮する場合においては注釈処理の利点は大きいと言えます。ネイティブイメージを作るにあたってのリフレクションの制約を回避できるからです。

コンパイル時にエラーを検出できる

この点については「Domaの開発で大切にしている10のこと」という記事の動かさないとわからないを減らすで紹介しました。

実行時のブートストラップの高速化

なぜ、実行時のブートストラップの高速化が可能かというと、注釈処理を使わなければ実行時に生成してメモリに保持するであろうメタデータをコンパイル時にクラスとして生成できるからです。

ブートストラップに比較的時間がかかるDBアクセスフレームワークの代表格はHibernateでしょう。Hibernateは、SessionFactory(JPAとして使う場合はEntityManagerFactory)を作るのにエンティティクラスの情報をリフレクションで読み取り様々な処理をします。エンティティクラスの数が少ない場合は全く気にならないと思いますが、数が多くなってくると顕著に初期化に時間がかかることに気づくでしょう。ログレベルをtraceなどにするとどんなことをしているのがよくわかると思います。

QuarkusのHibernate Extensionではその辺りの対策されているかもと思ってエンティティ100個くらい作ってサンプル動かしましたが、起動までに数十秒かかったので特に対策は入っていなさそうでした(JVM modeで試したのですが、Native modeならまた違ってくる可能性があります)。

一方、Domaの場合、実行時にはすでに存在するクラスをロードするだけで必要なメタデータを入手できます。しかも、ブートストラップ時に一度にロードするのではなく、必要に応じてクラスをロードするようになっているためエンティティクラスの数が多くなってもブートストラップ時間が伸びるということはありません。

注釈処理で気をつけたいこと

最も気をつけたいのは、注釈処理を有効にするためにIDEが特殊な設定を要求することです。また、ビルドツールにMavenを使うかGradleを使うかによっても気をつけるところが変わってきます。

冒頭で鬼門と書きましたが、Domaが動かないという現象のほとんどがこの設定に関することのように見受けられます。

おすすめのIDEとビルドツール

IDEでは、EclipseとIntelliJ IEDAのどちらでも動作確認しています。どちらが良いかは完全に好みですが、注釈処理を動かすにはEclipseの方が気を付けないといけないことが多いです。ただ、コツをつかめば大したことはないですし、Eclipseのインクリメンタルコンパイルによる注釈処理の実行はIDEAを使った場合に比べて迅速なフィードバックなので、気をつけるポイントが多いからという理由だけでEclipseを切り捨てるのは惜しいと思います(IDEAの場合は明示的にビルドしないと注釈処理が動かないが、Eclipseの場合はファイルをセーブするたびに動き、注釈処理によるエラーが迅速に開発者にフィードバックされます)。

ビルドツールは、GradleとMavenで動作確認しています。これもどちらでも好きな方を使っていただければいいのですが、EclipseとMavenの組み合わせは私個人でほとんどノウハウを持っていません。どうもM2Eclipseの挙動でハマることが多いようです。ただ、原因はSQLファイル周りだということがわかっているので、Criteira APIだけしか使わないのであればそんなに困らないかもしれません。

なお、GradleやMavenを使わずにEclipseやIEDAで動作させることも可能ですが全くおすすめしません。依存ライブラリをはじめ様々な設定で絶対にハマるのでGradleかMavenのどちらかは必ず使ってほしいところです。

まとめると、こんな感じになります。

IDE ビルドツール 説明
Eclipse Gradle 後述します。
Eclipse Maven ノウハウ不足。本記事では言及しない。情報募集中。
IDEA Gradle GradleプロジェクトとしてインポートすればOK。
IDEA Maven MavenプロジェクトとしてインポートすればOK。

Eclipse と Gradle を組み合わせる場合のポイント

まず、Gradleでプロジェクトを作ります。EclipseではなくGradleのプロジェクトとしてまず動作させることが重要です。雛形としては下記のプロジェクトを使うことをオススメします。

このプロジェクトはGradleのマルチプロジェクト構成になっています。もし作成したいものがマルチプロジェクト構成を必要としていなくても、このマルチプロジェクト構成は維持しておいて良いと思います。また、このプロジェクトはKotlin DSLで作られていますが、これも同様にリファクタリングのしやすさなどを考えてこのままKotlin DSLを使い続ける(Groovy DSLで書き換えない)で良いと考えます。さらに、このプロジェクトはGradle Wrapperを使っていますが、これも使わない理由はないのではと思います。

Gradleプロジェクトで最も重要なことは、com.diffplug.eclipse.aptというGradleプラグインを使うことです。このプラグインはEclipseで注釈処理を動かすための設定を出力してくれます。このプラグインはGradleのEclipseプロジェクトをフックするので、必要な設定ファイルを出力するには、./gradlew eclipseを実行すればOKです。念のため、常にcleanEclipseタスクとセットで
./gradlew cleanEclipse eclipseとするのがオススメです。

上述の設定ファイルを出力して初めてEclipseにプロジェクトをインポートします。EclipseはGradleのマルチプロジェクトを認識しないので、上述の雛形を使ったケースでは子プロジェクトのみEclipseにインポートされますが、特に問題にはならないと認識しています。

開発を進めていく過程で、依存ライブラリのバージョンが上がったり、注釈処理の設定を変更する必要が出てくるかもしれません。その場合、Eclipseから修正するのではなく、まずGradleのビルドスクリプトを修正します。その後に./gradlew cleanEclipse eclipseを実施してEclipseの設定ファイルを再出力し、Eclipseプロジェクトをリフレッシュ(設定ファイルのリロード)してください。常にGradleのビルドスクリプトを正とするのが非常に重要です

おわりに

Domaの注釈処理について説明しました。

最近ZulipというチャットサービスにDoma専用のルームを開設しました。もしDomaに関して質問などあればこのチャットルームでお気軽にどうぞ。

例えば、注釈処理の設定をGradleのビルドスクリプトに記述する方法などは世の中に情報少なめなので困ることあるかもしれませんが、質問もらえればアドバイスできそうです。

もちろん、DomaやDomaの関連プロダクトの開発に協力いただける方や情報を共有いただける方の参加もお待ちしています。

nakamura-to
プログラミング言語の特徴を生かしてデータベースアクセスを簡単にするためのライブラリを書くのが好き。これまで、Java、Kotlin、C#、F#、JavaScriptなどで実装経験がある。
isid
電通国際情報サービス(Information Services International-Dentsu, Ltd. 通称ISID)は、アメリカのGE社と電通の合弁会社として創業しました。 2000年に東証一部上場し、現在は単体で社員数約1,500人の会社です。ISIDにおける先端技術を活用した挑戦と事例、 検証した技術などを紹介します。
https://www.isid.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away