在JDK 9上声明maven依赖项以使用tools.jar

16

我有一个项目使用这种技术,在JDK 8及更早版本中运行良好。然而,在JDK 9中,该jar被删除了,不再起作用:

“dependencies.dependency.systemPath” for com.sun:tools:jar指向不存在的文件/usr/lib/jvm/java-9-jdk/../lib/tools.jar。请确认您正在使用JDK而不是仅使用JRE运行Maven。

(路径看起来很奇怪,尽管在JDK 9中没有tools.jar)

有哪些最佳实践可以跨JDK版本甚至JDK供应商工作? 我甚至没有在OpenJDK上找到任何解决JDK 9的方法(同时保持项目可在JDK 8上构建)。

3个回答

18
你遇到的问题是由于你使用的Java 9 EA版本中所包含的Project Jigsaw更改引起的。JEP 220对此进行了描述。
Removed: rt.jar and tools.jar部分更详细地描述了这一点,但Risks and Assumptions包含了一个很好的总结:

JDK和JRE映像将不再包含lib/rt.jarlib/tools.jarlib/dt.jar以及其他内部jar文件,如上所述。现有代码假定这些文件的存在可能无法正常工作。

因此,正如你所观察到的,这些文件已经不存在了。在下面还有更多内容:
在JDK镜像中,之前存储在lib/tools.jar中且只有在将该文件添加到类路径时才可见的类和资源文件现在可以通过系统类加载器或者在某些情况下是引导类加载器进行访问。但是,包含这些文件的模块不会被提及在应用程序类路径中,即不会出现在系统属性java.class.path的值中。
因此,来自tools.jar的类已经移动到模块中,但似乎用户可能无法使用它们。您应该从最近的Jigsaw构建中使用jdeps来确定模块依赖关系:
- 使用命令$jdeps -M -s $your_JAR来确定您的模块依赖关系。 - 使用命令jdeps -jdkinternals $your_JAR来确定对JDK内部API的依赖关系。
如果你很幸运,你使用的API已经发布(那么它将不会出现在第二次分析中),或者有一个公共替代品(第二次分析将列出)。否则,你应该考虑将此问题提交到 Jigsaw邮件列表,并在那里请求帮助,明确说明你正在使用哪些API以及用途。

谢谢,这对于理解我所依赖的内容非常有帮助,但是在tools.jar的情况下,如果我依赖于内置模块之一,它并不能帮助Maven进行构建。 - Oliver Gondža
这对于其他情境也很有帮助,比如(像我一样)你拥有现有的自定义 Javadoc doclet 并需要弄清如何在 Java 9 中编译它们。 - mhucka
1
“但似乎用户可能无法使用它们。” 这不是引用所说的。当迭代类路径时,您将找不到它们的类文件,这就是引用所说的。这总是适用于引导类,但现在,即使是由应用程序加载器加载的所有模块也适用,因为它们是通过模块路径而不是类路径加载的。” - Holger

10

结果表明,JDK 9 兼容的解决方案与原始技巧并没有太大的区别:

  <profiles>
    <profile>
      <id>jigsaw</id>
      <activation>
        <jdk>[1.9,)</jdk>
      </activation>
      <!-- No dependencies needed by Jigsaw -->
      <dependencies/>
    </profile>
    <profile>
      <id>default-jdk</id>
      <activation>
        <file>
          <exists>${java.home}/../lib/tools.jar</exists>
        </file>
      </activation>
      <dependencies>
        <dependency>
          <groupId>com.sun</groupId>
          <artifactId>tools</artifactId>
          <scope>system</scope>
          <version>1.6</version>
          <systemPath>${java.home}/../lib/tools.jar</systemPath>
        </dependency>
      </dependencies>
    </profile>
    <profile>
      <id>osx-jdk</id>
      <activation>
        <file>
          <exists>${java.home}/../Classes/classes.jar</exists>
        </file>
      </activation>
      <dependencies>
        <dependency>
          <groupId>com.sun</groupId>
          <artifactId>tools</artifactId>
          <scope>system</scope>
          <version>1.6</version>
          <systemPath>${java.home}/../Classes/classes.jar</systemPath>
        </dependency>
      </dependencies>
    </profile>
  </profiles>

如果整个依赖声明都移到配置文件中,就可以让不同的配置文件使用不同数量的依赖项。


我创建了一个可重用模块,以隐藏对依赖tools.jar的个别项目的复杂性:

<dependency>
  <groupId>com.github.olivergondza</groupId>
  <artifactId>maven-jdk-tools-wrapper</artifactId>
  <version>0.1</version>
</dependency>

0

你的解决方案(仅仅是权宜之计)被认为已经失效,并且在Java 9中将无法使用。你唯一能做的就是运行jdeps并将你的代码移动到公共API。


1
就理论而言,这是正确的。问题在于,“公共”API通常由tools.jar中的类提供,因此保持项目可构建需要解决这个问题,特别是对于旧版JDK。 - Oliver Gondža

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接