Declare maven dependency on tools.jar to work on JDK 9
Asked Answered
E

3

16

I have a project that uses this technique that work fine in JDK 8 and older. However, in JDK 9 this jar was removed and it does no longer work:

'dependencies.dependency.systemPath' for com.sun:tools:jar refers to a non-existing file /usr/lib/jvm/java-9-jdk/../lib/tools.jar. Please verify that you run Maven using a JDK and not just a JRE.

(The path looks strange, though there is no tools.jar in JDK 9)

What is the best practice that would work across JDK versions and perhaps even JDK vendors? I have not even found any workaround for JDK 9 on OpenJDK (while keeping the project buildable on JDK 8).

Evzone answered 6/2, 2016 at 10:51 Comment(0)
G
18

Your problems are caused by the Project Jigsaw changes that went into the Java 9 EA build you seem to have used. JEP 220 describes them.

The section Removed: rt.jar and tools.jar describes this in more detail but Risks and Assumptions contains a good summary:

JDK and JRE images will, as noted above, no longer contain the files lib/rt.jar, lib/tools.jar, lib/dt.jar, and other internal jar files. Existing code that assumes the existence of these files might not work correctly.

So as you observed, those files are gone. Further down:

Class and resource files previously found in lib/tools.jar and visible only when that file was added to the class path will now, in a JDK image, be visible via the system class loader or, in some cases, the bootstrap class loader. The modules containing these files will not, however, be mentioned in the application class path, i.e., in the value of the system property java.class.path.

So the classes from tools.jar are moved into modules but it seems like they might not be available to the user. You should use jdeps from a recent Jigsaw build...

  • ... to determine your module dependencies: $jdeps -M -s $your_JAR
  • ... to determine dependencies on JDK-internal APIs: jdeps -jdkinternals $your_JAR

If you're lucky, the API you are using was published (then it will not show up in the second analysis) or have a public alternative (which the second analysis would list ). Otherwise you should consider taking this to the Jigsaw mailing list and ask for help there, noting explicitly which APIs you are using and what for.

Giuliana answered 6/2, 2016 at 17:35 Comment(3)
Thanks, this is helpful in understanding what exactly I depend on but in case of tools.jar, it does not help to get maven to build in case I depend on one of the built-in modules.Septime
This is helpful to know in other contexts, such as if (like me) you have existing custom Javadoc doclets and need to figure out how to compile them with Java 9.Haiku
“but it seems like they might not be available to the user” That’s not what the cite said. You won’t find their class files when iterating over the class path, that’s what it said. That always applied to bootstrap classes, but nowadays, that also applies to all modules, even those loaded by the application loader, as they are loaded via the module path rather than class path.Phineas
E
10

It turns out the JDK 9 aware solution is not all that different from the original trick:

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

If whole dependency declarations are moved to the profile it enables different profiles to use different number of dependencies.


I created a reusable module to hide the complexity from individual project that depends on tools.jar:

<dependency>
  <groupId>com.github.olivergondza</groupId>
  <artifactId>maven-jdk-tools-wrapper</artifactId>
  <version>0.1</version>
</dependency>
Evzone answered 7/2, 2016 at 5:33 Comment(0)
M
0

You solution (mere workaround) is deemed to be broken and will not work with Java 9. All you can do is run jdeps and move your code to public APIs.

Moen answered 6/2, 2016 at 16:24 Comment(1)
This is true as far as the theory goes. The problem is the "public" APIs are often provided by classes in tools.jar so keeping the project buildable for older JDKs requires the this problem to be addressed.Septime

© 2022 - 2024 — McMap. All rights reserved.