如何在Java 9中运行时访问javax.annotation.Resource

时间:2017-09-30 10:51:05

标签: java java-9 java-module

我有一个测试:

public class ResourceTest {
    @Test
    public void test() throws ClassNotFoundException {
        Class.forName("javax.annotation.Resource");
    }
}

它尝试访问javax.annotation.Resource。在java 8中它起作用,但是在java 9中(我使用的是Oracle JDK 9),它失败了ClassNotFoundException。 正如此处Spring: @Resource injection stopped working under JDK9所解释的那样,JDK中的javax.annotation.Resource在Java 9中默认不可用。

我试图使用模块描述符访问它:

module test {
    requires java.xml.ws.annotation;
    requires junit;
}

在这里,我特意请求访问java.xml.ws.annotation模块(包含javax.annotation.Resource)。但测试仍然失败。

当我删除requires子句并添加包含javax.annotations.Resource的依赖项(作为库)时,它可以工作:

    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.1</version>
    </dependency>

当我同时添加它们时(pom.xmlrequires java.xml.ws.annotation中的Maven依赖关系),IDEA中的编译失败,并显示以下消息:

the unnamed module reads package javax.annotation from both java.xml.ws.annotation and java.annotation

但是Maven的构建仍然成功!

如果我通过命令行添加java.xml.ws.annotation模块,它可以工作(没有Maven依赖, requires子句):

mvn clean test -DargLine="--add-modules java.xml.ws.annotation"

我的模块描述有问题吗?如何在没有命令行开关的情况下访问JDK提供的javax.annotation.Resource

测试项目位于https://github.com/rpuch/test-resource-jdk9

2 个答案:

答案 0 :(得分:27)

这里要澄清一些困惑。您在问题中陈述的工作方式是替代方案,不应该像您已经看到的那样进行组合。

  

未命名的模块从两者中读取包javax.annotation   java.xml.ws.annotation和java.annotation

所以它的工作方式是:

您可以使用编译器args添加模块

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.7.0</version>
    <configuration>
        <release>9</release>
        <compilerArgs>
            <arg>--add-modules</arg>
            <arg>java.xml.ws.annotation</arg>
        </compilerArgs>
    </configuration>
</plugin>

利用javax.xml.ws.annotation作为upgradeable module,这是您何时可以使用依赖

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.1</version>
</dependency>

理想情况下,这是一个可以选择的选项,因为前者只是使用标记为forRemoval的{​​{3}}模块的替代方案。

  

所以必需的条款本身不足以获得访问权限   module ...对于所有JDK提供的模块都是如此(不包括   java.base),或者仅适用于已弃用的模块?

不,requires只是声明的一部分。 [想想这个,在JDK 9之前,如果你在你的类中使用了一个未添加为库(classpath)的语句import some.foo.bar;会有效吗?]。标记为必需的模块必须位于模块路径上才能访问它。

更新 - 使用JDK / 11或更高版本(其中JEP为@Deprecated的目标是不再支持第一个选项。

答案 1 :(得分:1)

对于gradle构建,将以下内容添加到build.gradle中:

compile 'javax.annotation:jsr250-api:1.0'

tasks.withType(AbstractCompile) {
    options.compilerArgs += ["--add-modules", "java.xml.bind"]
}

tasks.withType(Test) {
    jvmArgs += ["--add-modules", "java.xml.bind"]
}