Java 编译器不允许在使用 JPMS 的项目中使用来自“compileOnly”模块的带有“Source”保留的注释

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

注释处理器和编译器插件通常定义具有 sourceclass 保留的注释。这些注解不会在运行时公开,因此不需要将它们包含在运行时类路径中;它们可以通过 compileOnly 在 Gradle 构建文件中使用。此外,无需在 module-info 文件中声明它们的用途。然而,在存在 module-info 文件的情况下,Java 编译器要求将注释 类 包含在运行时类路径中——它们必须在模块信息中声明,这意味着必须使用 implementation 而不是 compileOnly 从 Gradle 访问它们。这似乎是编译器对 JPMS 的支持中的一个漏洞。或者,对于这种奇怪的行为有什么好的解释吗?

这是一个例子。

package com.example;
...

@Retention(RetentionPolicy.SOURCE)
public @interface Example {
...
}

com.example.Example 注释在依赖项 my-annotation-proc 中定义。

dependencies {
    compileOnly 'com.example:my-annotation-proc:0.1-SNAPSHOT'
    annotationProcessor 'com.example:my-annotation-proc:0.1-SNAPSHOT'
}

ExampleAnnotation 在 Foo.java 中的用法。

package abc;

public class Foo {
  
  @com.example.Example
  public void something() {
    ...
  }
}

module-info.java 文件应该 而不是 需要 requires 才能使用注释。

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

编译项目会产生编译错误,指示 com.example 不可见等

requires 指令对于 任何 依赖项都是强制性的,而不仅仅是运行时依赖项。

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.

我不知道使用 requires static my.annotation.proc; 是否可以解决您使用 Gradle 的问题,但这应该是在语言级别处理的方式。