A new maven plugin that uses the jdeps utility to find uses of JDK Internal APIs has been released. When activated, the plugin will make a maven build fail if the code is found to use any internal API. Internal APIs will be inaccessible as of Java 9, therefore this plugin helps developers make their code compatible with the next version of Java. Despite its 3.0.0 label, this is the first release of the plugin.

As indicated in the project page, the plugin makes two goals available to the user: jdkinternals, and test-jdkinternals. The former will check whether the main code makes any reference to internal APIs, while the latter will do the the same for the test code; jdkinternals is linked by default to the maven phase process-classes (which runs right after compilation), while test-jdkinternals is to the phase process-test-classes (which runs right after compilation of test code). The default configuration can be used by referring to the plugin and activating both goals in the following manner:

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jdeps-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <goals> <goal>jdkinternals</goal> <goal>test-jdkinternals</goal> </goals> </execution> </executions> </plugin> <!— Other plugins —> </plugins> </build>

As an example, let’s assume a project which uses the internal class sun.misc.BASE64Decoder. When configured to use the JDeps Plugin, maven will fail indicating the following reason:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-jdeps-plugin:3.0.0:jdkinternals (default) on project <project-name>: Found offending packages: [ERROR] sun.misc -> JDK internal API (rt.jar) [ERROR] -> [Help 1]

As part of the output, maven will also list, for each package in the project, all the individual packages that are being referenced by the code, together with the source of that package. As part of that output we will find the following for the package or packages using BASE64Decoder:

package.name (classes) [... other packages ...] -> sun.misc JDK internal API (rt.jar)

This provides a hint to the developer about the location of the problem. However there is a way to obtain more details.

As mentioned before, the plugin is based on the tool jdeps, provided by Oracle as part of JDK 8. If the plugin forces the build to fail due to references to internal APIs being found, the user can then use jdeps to try and find more information about the offending APIs; on occasions, jdeps will even be able to point to a non-internal alternative, if there is one available. Following the same example of BASE64Decoder above, running jdeps with the right option would show the following:

jdeps -jdkinternals target/classes/* [...] JDK Internal API Suggested Replacement ---------------- --------------------- sun.misc.BASE64Decoder Use java.util.Base64 @since 1.8

Unfortunately, when a replacement for an internal API is not yet available, as is the case for sun.misc.Unsafe, the plugin has the potential to block development. For this reason, the plugin is likely to be most useful to those who don’t currently use any internal APIs and want to make sure that they won’t start using them. Martijn Verburg, co-founder of jClarity and Java Champion since 2012, encouraged all developers in a recent communication to use the Apache Maven JDeps Plugin to ease the effort of a future migration to Java 9.