Identifying Code Compatibility Issues

Eclipse Neon will require a Java 8 runtime, which will help foster more adoption of the latest Java runtime. The timing is appropriate to look forward at JDK 9 and ensure that code is ready to run on the next major version of the Java platform. One major consideration for developers is to begin migrating away from JDK internal APIs that are always subject to change or removal. JDK 8 and JDK 9 already include a tool called jdeps that can scan bytecode (including libraries) to identify where applications rely on these JDK internal APIs. The OpenJDK wiki includes a list of known replacements for many internal APIs that developers can use instead.

Internal APIs are most often inside packages such as sun.*, com.sun.*, or other similar designations. These APIs represent implementation details and are not considered part of the public API and may change, move, or disappear without notice. The jdeps tool will walk through and perform a static analysis to identify calls into any of these internal APIs. This is effective for most cases but does not cover the less-frequent runtime-generated invocations like Class.forName, Reflection, or MethodHandles.

Developers can run jdeps through a command line. For example to look through all JAR files in a directory, the following command will identify internal API usage.

jdeps -cp . -jdkinternals *.jar

Sample output snippet:

hadoop-common-2.2.0.jar -> ...\lib\rt.jar
org.apache.hadoop.io.FastByteComparisons$... (hadoop-common-2.2.0.jar)
    -> com.sun.jndi.ldap.LdapCtxFactory JDK internal API (rt.jar)


As we guide developers away from using internal APIs, the results will be more successful by recommending what to use instead. The jdeps command output also offers suggestions based on its analysis:

JDK Internal API Suggested Replacement
sun.misc.Cleaner Use java.lang.ref.PhantomReference @since 1.2

The jdeps command line will suit many cases. Robert Scholte has done excellent work on a jdeps maven plugin to assist developers looking at build integration.

In some cases, the suggested replacement may not be available until JDK 9. Library developers are not expected to maintain two copies of their code and should instead use another new feature: multi-release JAR files. Multi-Release JAR files are intended to help library developers adopt new language features and APIs without breaking backwards compatibility. For example, java.util.Base64 was introduced in JDK 8 as a way to replace three APIs in sun.misc and internal Apache XML. Access to those internal APIs will be restricted in JDK 9 and developers – As JDK 9 limits access to its internals, how should code be updated in a way that does not break backwards compatibility with versions before java.util.Base64 was introduced (such as JDK 7)?

Backwards compatibility can be preserved by using jdeps to see where these internal APIs are used and then making a multi-release JAR. The application would be written to have two class files:

  • com/example/MyClass.class – this would be loaded by older JDK implementations, such as JDK 7 and JDK 8. This class may continue the bad practice of using the older sun.misc.BASE64Decoder.
  • META-INF/versions/8/com/example/MyClass.class – this class would use the java.util.Base64 that was introduced in Java 8. It will be loaded by JDK versions that understand multi-release JAR files.

Oracle has also been active in the engaging open source projects through the OpenJDK Quality Outreach Campaign. This group has coordinated with a number of projects to help guide them on running jdeps and integrate early access of JDK 9 into their test process. Open Source project maintainers should consider joining the list to learn ways to test upcoming changes. The jdeps tool is available for use now in JDK 8 and even better, early access of JDK 9.

About the Authors

Erik Costlow

Erik Costlow
Oracle