英文:
The Java compiler does not allow usage of an annotation with `Source` retention from a `compileOnly` module for a project using JPMS
问题
注解处理器和编译器插件通常使用source
或class
保留策略定义注解。这些注解在运行时不可见,因此无需将它们包含在运行时类路径中;可以在Gradle构建文件中通过compileOnly
来使用它们。此外,在存在module-info
文件的情况下,Java编译器要求将注解类包含在运行时类路径中 - 必须在module-info
中声明它们,这意味着它们必须从Gradle中使用implementation
而不是compileOnly
。这似乎是编译器对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'
}
在 Foo.java
中使用 ExampleAnnotation
。
package abc;
public class Foo {
@com.example.Example
public void something() {
...
}
}
module-info.java
文件不应该需要为注解的使用添加 requires
。
module MyProject {
// 不应该需要这个。
// 而且,添加它需要在Gradle中添加 `implementation` 依赖项,将其引入到不应该存在的运行时中。
//requires my.annotation.proc;
}
编译项目会产生一个编译错误,指示 com.example
不可见等问题。
英文:
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.
答案1
得分: 4
requires
指令对于任何依赖项都是强制的,不仅限于运行时依赖。
与JLS,§7.7.1进行比较:
7.7.1. 依赖
requires
指令指定当前模块所依赖的模块的名称。…
requires
关键字后面可以跟着修饰符static
。这表示依赖在编译时是强制的,但在运行时是可选的。
我不知道在Gradle方面是否使用 requires static my.annotation.proc;
能够解决你的问题,但这是语言层面上应该处理的方式。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论