[JAVA] Find out about annotationProcessor for Gradle 5.0

Deprecated warning

When using annotation processing in recent Gradle (my environment is 4.10.2), the following message appears.

> 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

I'm using a feature that is incompatible with Gradle 5.0, so if you want to check the details, specify the --warning-mode all option.

When executed with options specified, the output is as follows.

> 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.

It seems that Gradle 5.0 will no longer support getting the annotation processor from the compile-time classpath. When I tried running it with RC version of 5.0, it was certainly ignored.

Instead, specify it in ʻannotation processor path. Or, if your project doesn't use annotation processing, add -proc: none` to the compile options.

Gradle 5.0: Planned behaviour of ignoring jars with annotation processors not okay. · Issue #5056 · gradle/gradle

According to the comments in this issue, it seems that the reason is to support incremental annotation processors (I'm not sure).

How to respond

Convenient declaration of annotation processor dependencies | Gradle 4.6 Release Notes

As of Gradle 4.6, if you install a Java plugin, you can set a configuration called ʻannotationProcessor`.

Dependency configurations | The Java Plugin

Dependent libraries that provide annotation processing should be specified in ʻannotationProcessor instead of ʻimplementation.

By the way, ʻannotationProcessoris the configuration for the main code, so if you want to apply annotation processing to the test code, specify it intestAnnotationProcessor`.

** Android annotationProcessor **

When I googled, [The story of migration to Android Plugin for Gradle 3.0.0](https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration?hl=ja# annotationProcessor_config) also shows ʻannotationProcessor`, but is this something else? (Not familiar with Android)

At least, Gradle's JavaPlugin has ʻannotationProcessor` like a commit on December 15, 2017. For Android, the release of 3.0.0 is October 2017-like, so Android comes first. ??

Correspondence method changes depending on the method of providing annotation processing (I think)

I actually tried various things and noticed, but even if it is just annotation processing, I think that the specification method will change a little depending on the provision method etc. (It is a conclusion reached as a result of personal trial and error, so guarantee of correctness Story).

When classified, I feel that they are divided as follows.

--The library itself and annotation processing are provided in separate jars --The library itself and annotation processing are provided in the same jar

Implementation for verification

Folder structure


|-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

—— Consists of 3 multi-projects - combined --A project that provides the main body and annotation processing in one jar - separated --A project that provides the main body and annotation processing in different jars - main --Projects that use each annotation process --CombinedProcessor.java and SeparatedProcessor.java are classes that implement annotation processing respectively. --Combined.java and Separated.java are the annotations to be processed respectively. --Foo.java sets both annotations to be processed.

Foo.java


package main;

import combined.core.Combined;
import separated.core.Separated;

@Combined
@Separated
public class Foo {}

--build.gradle looks like this

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 {
        ... //The settings here will be described later.
    }
}

The library body and annotation processing are provided in separate jars

In this case, specify the jar of the main body in ʻimplementation [^ 1] and the jar for annotation processing in ʻannotationProcessor.

[^ 1]: Set to compileOnly for libraries that are only needed at compile time

build.gradle


project(":main") {
    dependencies {
        implementation project(":separated:core")
        annotationProcessor project(":separated:apt")
    }
}

Verification


> gradle :main:build --warning-mode all
...

> Task :main:compileJava
Caution:SeparatedProcessor!!
Caution:SeparatedProcessor!!

BUILD SUCCESSFUL in 4s

Complete without warning.

The library that corresponds to this pattern is Dagger introduced in the official document.

The library itself and annotation processing are provided in the same jar

In this case, specify the same dependency for both ʻimplementation and ʻannotationProcessor.

build.gradle


project(":main") {
    dependencies {
        implementation project(":combined")
        annotationProcessor project(":combined")

        ...
    }
}

Execution result


> gradle :main:build --warning-mode all
...

> Task :main:compileJava
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!
Caution:CombinedProcessor!!
Caution: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

I got a warning. If you look closely, you will see a warning printed within the task of compileTestJava (compileJava completes without warning).

The Java Plugin Documentation (https://docs.gradle.org/4.10.2/userguide/java_plugin.html#tab:configurations) illustrates the dependencies of each configuration. Extracting only the relevant parts this time, it is as follows (red is the deprecated configuration).

annotationProcessor.jpg

The dependency specified in ʻimplementation is also used in testCompileClasspath` as it is. Therefore, it seems that the annotation process is detected from the classpath during the test and a warning is issued.

What should i do?

If needed only at compile time

If you only need the jar at compile time, you can avoid the warning by using compileOnly instead of ʻimplementation` (or rather, I think that's the correct setting). For example, Lombok.

build.gradle


dependencies {
    compileOnly project(":combined")
    annotationProcessor project(":combined")

    ...
}

Execution result


> gradle :main:build --warning-mode all
...

> Task :main:compileJava
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!

BUILD SUCCESSFUL in 5s

The warning is gone.

ignore

If your test code doesn't use annotation processing, ignoring the warning may be an option. After all, if it is ignored from 5.0, the warning will not be issued at the time of raising it to 5.0, and it seems that it will settle down to a state where there is no problem in movement.

When I tried it with the RC version of 5.0, the warning disappeared and only the annotation process of main worked.

5.Result of running with 0RC


> gradle --version
------------------------------------------------------------
Gradle 5.0-rc-1
------------------------------------------------------------

...

> gradle :main:build
...

> Task :main:compileJava
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!

BUILD SUCCESSFUL in 4s

If you need it at runtime

The compileOnly specification cannot be used if a dependency is still required at runtime. For example, Doma2 is one of them.

When this happens, I think it's best to ignore the warnings in the test code. However, if it cannot be ignored, I think that the method of adding the specification to disable the annotation processor to the compile option given in the first warning message will be taken.

build.gradle


dependencies {
    implementation project(":combined")
    annotationProcessor project(":combined")

    ...
}

compileTestJava {
    //For compile options during testing`-proc:none`Add
    options.compilerArgs += ["-proc:none"]
}

Execution result


> gradle :main:build --warning-mode all
...

> Task :main:compileJava
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!
Caution:CombinedProcessor!!
Caution:SeparatedProcessor!!

BUILD SUCCESSFUL in 5s

There is no warning.

Recommended Posts

Find out about annotationProcessor for Gradle 5.0
Find out about Docker
Find out about environment variables (memo)
Find out about instance methods and self
Introduction to kotlin for iOS developers ③-About gradle
About for statement and if statement
[Gradle] About Java plug-in tasks
Gradle settings for using JUnit 5
Gradle TIPS collection (for myself)
About Popover fix for iOS 13
[Ransack] Watch out for ransackable_scopes!