Annotation processors and compiler plugins often define annotations with source or class retention. These annotations are not exposed at runtime, thus there is no need to include them in the runtime classpath; they can be used via compileOnly in a Gradle build file. Additionally, there is no need to declare their use in the module-info file. Yet, in the presence of a module-info file, the Java compiler requires the annotation classes to be included in the runtime classpath -- they must be declared in the module-info, which means they must be accessed from Gradle with implementation instead of compileOnly. This appears to be a hole in the compiler's support for JPMS. Or, is there a good explanation for this odd behavior?
Here's an example.
package com.example;
...
@Retention(RetentionPolicy.SOURCE)
public @interface Example {
...
}
The com.example.Example annotation is defined in dependency my-annotation-proc.
dependencies {
compileOnly 'com.example:my-annotation-proc:0.1-SNAPSHOT'
annotationProcessor 'com.example:my-annotation-proc:0.1-SNAPSHOT'
}
Usage of ExampleAnnotation in Foo.java.
package abc;
public class Foo {
@com.example.Example
public void something() {
...
}
}
The module-info.java file should not need a requires for usage of the annotation.
module MyProject {
// Should be no need for this.
// Plus, adding it requires an `implementation` dependency in Gradle, which brings it into runtime where it does not belong.
//requires my.annotation.proc;
}
Compiling the project produces a compile error indicating the com.example is not visible etc.