非推奨の警告
最近の Gradle (自分の環境は、 4.10.2)で注釈処理を利用していると、次のようなメッセージが出る。
> gradle compileJava
...
Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/4.10.2/userguide/command_line_interface.html#sec:command_line_warnings
Gradle 5.0 で非互換になる機能を利用しているので、詳細を確認したければ --warning-mode all
オプションを指定しろとのこと。
オプションを指定して実行すると、次のように出力される。
> gradle compileJava --warning-mode all
...
Detecting annotation processors on the compile classpath has been deprecated.
Gradle 5.0 will ignore annotation processors on the compile classpath.
The following annotation processors were detected on the compile classpath:
'combined.apt.CombinedProcessor' and
'separated.apt.SeparatedProcessor'.
Please add them to the annotation processor path instead.
If you did not intend to use annotation processors, you can use the '-proc:none' compiler argument to ignore them.
なんでも、 Gradle 5.0 からはアノテーションプロセッサをコンパイル時のクラスパスから取得する方法がサポートされなくなるらしい。
試しに 5.0 の RC 版 で実行したら、確かに無視されるようになっていた。
代わりに、 annotation processor path
に指定しろとのこと。
もしくは、別に注釈処理を使っていないプロジェクトであれば、 -proc:none
をコンパイルオプションに追加しろとのこと。
こちらの Issue に書き込まれているコメントによると、インクリメンタルな注釈処理(incremental annotation processors)をサポートするのが理由らしい(よくわかってない)。
対応方法
Convenient declaration of annotation processor dependencies | Gradle 4.6 Release Notes
Gradle 4.6 の時点で Java プラグインを入れると annotationProcessor
という configuration が設定できるようになっている。
Dependency configurations | The Java Plugin
注釈処理を提供する依存ライブラリは、 implementation
ではなく annotationProcessor
に指定すれば良い。
ちなみに、 annotationProcessor
は main のコード用の configuration なので、 test のコードに対して注釈処理を適用したい場合は testAnnotationProcessor
に指定する。
Android の annotationProcessor
ググってると、Android Plugin for Gradle 3.0.0 へのマイグレーションの話 でも同じように annotationProcessor
が出てくるけど、これはまた別物?(Android 事情に疎い)
少なくとも、 Gradle の JavaPlugin に annotationProcessor
が入ったのは 2017年12月15日のコミットっぽい。Android の方は 3.0.0 のリリースが 2017年10月っぽいので、 Android の方が先?
注釈処理の提供方法によって対応方法が変わる(と思う)
実際にいろいろ試してみて気づいたが、単に注釈処理といっても、その提供方法などによって、ちょっと指定方法が変わってくると思う(個人的な試行錯誤の結果たどり着いた結論なので、正しさの保証はなし)。
分類すると、次のような感じで分かれる気がする。
- ライブラリ本体と注釈処理が別々の jar で提供されている
- ライブラリ本体と注釈処理が同じ jar で提供されている
検証用の実装
|-build.gradle
|-settings.gradle
|-combined/
| `-src/main/
| |-java/
| | `-combined/
| | |-apt/
| | | `-CombinedProcessor.java
| | `-core/
| | `-Combined.java
| `-resources/
| `-META-INF/services/
| `-javax.annotation.processing.Processor
|
|-separated/
| |-apt/
| | `src/main/
| | |-java/
| | | `-separated/apt/
| | | `-SeparatedProcessor.java
| | `-resources/
| | `-META-INF/services/
| | `-javax.annotation.processing.Processor
| `-core/
| `-src/main/java/
| `-separated/core/
| `-Separated.java
|
`-main/
`-src/
|-main/java/
| `-main/
| `-Foo.java
`-test/java/
`-main/
`-FooTest.java
- 3つのマルチプロジェクトから成る
-
combined
- 本体と注釈処理を1つの jar で提供するプロジェクト
-
separated
- 本体と注釈処理を異なる jar で提供するプロジェクト
-
main
- それぞれの注釈処理を利用しているプロジェクト
-
-
CombinedProcessor.java
とSeparatedProcessor.java
が、それぞれ注釈処理を実装したクラス -
Combined.java
とSeparated.java
が、それぞれ処理対象となるアノテーション -
Foo.java
は、両方のアノテーションを設定して処理対象になるようにしている
package main;
import combined.core.Combined;
import separated.core.Separated;
@Combined
@Separated
public class Foo {}
-
build.gradle
は次のような感じ
subprojects {
apply plugin: "java"
sourceCompatibility = 11
targetCompatibility = 11
compileJava.options.encoding = "UTF-8"
}
project(":separated:apt") {
dependencies {
implementation project(":separated:core")
}
}
project(":main") {
dependencies {
... // ここの設定は後述
}
}
ライブラリ本体と注釈処理が別々の jar で提供されている
この場合は、 implementation
1 に本体の jar を、 annotationProcessor
に注釈処理用の jar を指定すればいい。
project(":main") {
dependencies {
implementation project(":separated:core")
annotationProcessor project(":separated:apt")
}
}
> gradle :main:build --warning-mode all
...
> Task :main:compileJava
注意:SeparatedProcessor!!
注意:SeparatedProcessor!!
BUILD SUCCESSFUL in 4s
警告なく完了する。
※CombinedProcessor
の方は一時的に依存や実装を外している
このパターンに該当するライブラリとしては、公式ドキュメントで紹介されている Dagger などが該当する。
ライブラリ本体と注釈処理が同じ jar で提供されている
この場合は、 implementation
と annotationProcessor
の両方に同じ依存対象を指定する。
project(":main") {
dependencies {
implementation project(":combined")
annotationProcessor project(":combined")
...
}
}
> gradle :main:build --warning-mode all
...
> Task :main:compileJava
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
> Task :main:compileTestJava
Detecting annotation processors on the compile classpath has been deprecated. Gradle 5.0 will ignore annotation processors on the compile cl
asspath. The following annotation processors were detected on the compile classpath: 'combined.apt.CombinedProcessor'. Please add them to t
he annotation processor path instead. If you did not intend to use annotation processors, you can use the '-proc:none' compiler argument to
ignore them.
BUILD SUCCESSFUL in 4s
警告が出た。
よく見ると、 compileTestJava
のタスク内で警告が出力されている(compileJava
の方は警告なしで完了している)。
Java プラグインのドキュメント に、各 configuration の依存関係が図解されている。
今回関係する部分だけを抽出すると、次のようになっている(赤いのは非推奨の configuration)。
implementation
に指定した依存関係は、そのまま testCompileClasspath
でも利用される。
従って、テストのときにクラスパスから注釈処理が検出されて警告が出てしまっているっぽい。
どうすべきか?
コンパイル時だけ必要な場合
jar が必要なのがコンパイル時のみであれば、 implementation
の代わりに compileOnly
を使うことで警告表示を回避できる(というか、その方が設定として正しい気がする)。
例えば、 Lombok がこれに該当する。
dependencies {
compileOnly project(":combined")
annotationProcessor project(":combined")
...
}
> gradle :main:build --warning-mode all
...
> Task :main:compileJava
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
BUILD SUCCESSFUL in 5s
警告は出なくなった。
無視する
テストコードで注釈処理を利用していないのであれば、警告は無視するのも選択肢としてありかなとも思う。
結局、 5.0 からは無視されるのであれば、 5.0 に上げた時点で警告も出なくなり、動きとしても問題ない状態に落ち着きそうな気がする。
一応 5.0 の RC 版で試したら、警告はなくなり main の方の注釈処理だけが動いてくれた。
> gradle --version
------------------------------------------------------------
Gradle 5.0-rc-1
------------------------------------------------------------
...
> gradle :main:build
...
> Task :main:compileJava
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
BUILD SUCCESSFUL in 4s
実行時も必要な場合
実行時も依存対象が必要な場合は、 compileOnly
の指定は利用できない。
例えば、 Doma2 がこれに該当する。
こうなると、テストコードで出る警告は無視するのが一番良い気もする。
しかし、どうしても無視できないのであれば、最初の警告メッセージで出ていたコンパイルオプションにアノテーションプロセッサを無効にする指定を追加する方法を取ることになると思う。
dependencies {
implementation project(":combined")
annotationProcessor project(":combined")
...
}
compileTestJava {
// テスト時のコンパイルオプションに `-proc:none` を追加
options.compilerArgs += ["-proc:none"]
}
> gradle :main:build --warning-mode all
...
> Task :main:compileJava
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
注意:CombinedProcessor!!
注意:SeparatedProcessor!!
BUILD SUCCESSFUL in 5s
警告は出ない。
-
コンパイル時のみ必要なライブラリの場合は
compileOnly
に設定する ↩