简体   繁体   中英

The Java compiler does not allow usage of an annotation with `Source` retention from a `compileOnly` module for a project using JPMS

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.

A requires directive is mandatory for any dependency, not just runtime dependencies.

Compare with JLS, §7.7.1 :

7.7.1. Dependences

The requires directive specifies the name of a module on which the current module has a dependence.

The requires keyword may be followed by the modifier static . This specifies that the dependence, while mandatory at compile time, is optional at run time.

I don't know whether using requires static my.annotation.proc; solves your problem with Gradle, but that's how it is supposed to be handled at the language level.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM