How Java 9 And Project Jigsaw May Break Your Code
Java 9 looms on the horizon and it will come with a completed Project Jigsaw. I didn’t pay much attention to it until I learned from a recent discussion on the OpenJFX mailing list that it may break existing code. This is very unusual for Java so it piqued my interest.
I went reading the project’s JEPs and some related articles and came to the conclusion that, yes, this will break existing code. It depends on your project whether you will be affected but you might be and it might hurt.
Overview
After a cursory introduction to what Project Jigsaw is about, I will describe the potentially breaking changes.
I compiled that list of changes from the available documents. There is of course no guarantee that I caught everything and since I am unfamiliar with some of the concepts, I might have gotten some facts wrong. Caveat emptor.
If you find a mistake or think something could be made clearer or more precise, leave a comment and I will be happy to include your input.
Project Jigsaw
I might write a more detailed description of Project Jigsaw at some point, but for now I’ll be lazy and simply quote:
The primary goals of this Project are to:
- Make the Java SE Platform, and the JDK, more easily scalable down to small computing devices;
- Improve the security and maintainability of Java SE Platform Implementations in general, and the JDK in particular;
- Enable improved application performance; and
- Make it easier for developers to construct and maintain libraries and large applications, for both the Java SE and EE Platforms.
To achieve these goals we propose to design and implement a standard module system for the Java SE Platform and to apply that system to the Platform itself, and to the JDK. The module system should be powerful enough to modularize the JDK and other large legacy code bases, yet still be approachable by all developers.
If you want to know more about the project, check out its site and especially the list of goals and requirements (current version is draft 3 from July 2014).
The main thing to take away here is the module system. From version 9 on Java code can be (and the JRE/JDK will be) organized in modules instead of JAR files.
Breaking Code
This sounds like an internal refactoring so why would it break existing code? Well, it doesn’t do that necessarily and compatibility is even one of the project’s central requirements (as usual for Java):
An application that uses only standard Java SE APIs, and possibly also JDK-specific APIs, must work the same way […] as it does today.
The important part is the qualification “only standard APIs”. There are plenty of ways to create applications which for some critical detail rely on unspecified or deprecated properties like non-standard APIs, undocumented folder structures and internal organizations of JAR files.
So let’s see the potentially breaking changes. For more details, make sure to check the project’s site, especially JEP 220, which contains a more precise description of most of what follows.
Internal APIs Become Unavailable
With JAR files any public class is visible anywhere in the JVM. This severely limits the ability of JDK-implementations to keep internal APIs private. Instead many are accessible and they are often used for a variety of reasons (e.g. to improve performance or work around [former] bugs in the Java runtime; the Java FAQ explains why that may be a bad idea).
This changes with modules. Every module will be able to explicitly declare which types are made available as part of its API. The JDK will use this feature to properly encapsulate all internal APIs which will hence become unavailable.
This may turn out to be the biggest source of incompatibilities with Java 9. It surely is the least subtle one as it causes compile errors.
To prepare for Java 9 you could check your code for dependencies upon internal APIs. Everything you find must be replaced one way or another. Some workarounds might have become unnecessary. Other classes might find their way into the public API. To find out whether this is the case, you will have to research and maybe resort to asking this on the OpenJDK mailing list for the functionality you are interested in.
Internal APIs
So what are internal APIs? Definitely everything that lives in a sun.*
-package. I could not confirm whether everything in com.sun.*
is private as well – surely some parts are but maybe not all of them?
Update (5th of May, 2015): This got cleared up in a comment by Stuart Marks as follows:
Unfortunately, com.sun is a mixture of internal and publicly supported (“exported”) APIs. An annotation @jdk.Exported distinguishes the latter from internal APIs. Note also that
com.sun.*
packages are only part of the Oracle (formerly Sun) JDK, and they are not part of Java SE.So if starts with
com.sun.*
, it won’t exist on any non-Oracle JDK. And if it belongs to one of those packages and is not annotated with@jdk.Exported
, it will be unaccessible from Java 9 on.
Two examples, which might prove especially problematic, are sun.misc.Unsafe
and everything in com.sun.javafx.*
. Apparently the former is used in quite a number of projects for mission and performance critical code. From personal experience I can say that the latter is a crucial ingredient to properly building JavaFX controls (e.g. all of ControlsFX depends on these packages). It is also needed to work around a number of bugs.
Both of these special cases are considered for being turned into public API (see for Unsafe and for JavaFX – although some people would rather see Unsafe die in a fire).
Tool Support
Fortunately you don’t have to find these dependencies by hand. Since Java 8 the JDK contains the Java Dependency Analysis Tool jdeps (introduction with some internal packages, official documentation for windows and unix), which can list all packages upon which a project depends.
If you run it with the parameter -jdkinternals, it will output all internal APIs your project uses – exactly the ones which you will have to deal with before Java 9 rolls around.
Update (15th of May, 2015): JDeps does not yet recognize all packages which will be unavailable in Java 9. This affects at least those which belong to JavaFX as can be seen in JDK-8077349. I could not find other issues regarding missing functionality (using this search).
Update (11th of May, 2015): I created a Maven plugin which uses JDeps to discover problematic dependencies and breaks the build if it finds any. See the release post for details.
Merge Of JDK And JRE
The main goal of Project Jigsaw is the modularization of the Java Platform to allow the flexible creation of runtime images. As such the JDK and JRE loose their distinct character and become just two possible points in a spectrum of module combinations.
This implies that both artifacts will have the same structure. This includes the folder structure and any code which relies on it (e.g. by utilizing the fact that a JDK folder contains a subfolder jre) will stop working correctly.
Internal JARs Become Unavailable
Internal JARs like lib/rt.jar and lib/tools.jar will no longer be accessible. Their content will be stored in implementation-specific files with a deliberately unspecified and possibly changing format.
Code which assumes the existence of these files, will stop working correctly. This might also lead to some transitional pains in IDEs or similar tools as they heavily rely on these files.
New URL Schema For Runtime Image Content
Some APIs return URLs to class and resource files in the runtime (e.g. ClassLoader.getSystemResource
). Before Java 9 these are jar URLs and they have the following form:
jar:file:<path-to-jar>!<path-to-file-in-jar>
Project Jigsaw will use modules as a container for code files and the individual JARs will no longer be available. This requires a new format so such APIs will instead return jrt URLs:
jrt:/<module-name>/<path-to-file-in-module>
Code that uses the instances returned by such APIs to access the file (e.g. with URL.getContent
) will continue to work as today. But if it depends on the structure of jar URLs (e.g. by constructing them manually or parsing them), it will fail.
Removal Of The Endorsed Standards Override Mechanism
Some parts of the Java API are considered Standalone Technologies and created outside of the Java Community Process (e.g. JAXB). It might be desirable to update them independently of the JDK or use alternative implementations. The endorsed standards override mechanism allows to install alternative versions of these standards into a JDK.
This mechanism is deprecated in Java 8 and will be removed in Java 9. Its replacement are upgradeable modules.
If you’ve never heard about this, you’re probably not using it. Otherwise you might want to verify whether the implementation you are using will be made into an upgradeable module.
Removal Of The Extension Mechanism
With the extension mechanism custom APIs can be made available to all applications running on the JDK without having to name them on the class path.
This mechanism is deprecated in Java 8 and will be removed in Java 9. Some features which are useful on their own will be retained.
If you’ve never heard about this, you’re probably not using it. Otherwise you might want to check JEP 220 for details.
Preparations For Java 9
Together these changes impose a risk for any large project’s transition to Java 9. One way to assess and reduce it could be an “update spike”: Use jdeps to identify dependencies on internal APIs. After fixing these, invest some time to build and run your project with one of the Java 9 early access builds. Thoroughly test relevant parts of the system to get a picture of possible problems.
Information gathered this way can be returned to the project, e.g. by posting it on the Jigsaw-Dev mailing list. To quote the (almost) final words of JEP 220:
It is impossible to determine the full impact of these changes in the abstract. We must therefore rely upon extensive internal and—especially—external testing. […] If some of these changes prove to be insurmountable hurdles for developers, deployers, or end users then we will investigate ways to mitigate their impact.
Reflection & Lookout
We have seen that Project Jigsaw will modularize the Java runtime. Internal APIs (packages sun.*
and maybe com.sun.*
) will be made unavailable and the internal structure of the JRE/JDK will change, which includes folders and JARs. Following their deprecation in Java 8, the endorsed standards override mechanism and the extension mechanism will be removed in Java 9.
If you want to help your friends and followers to prepare for Java 9, make sure to share this post.
So far we focused on the problematic aspects of Project Jigsaw. But that should not divert from the exciting and – I think – very positive nature of the planned changes. After reading the documents, I am impressed with the scope and potential of this upcoming Java release. While it is likely not as groundbreaking for individual developers as Java 8, it is even more so for everyone involved in building and deploying – especially of large monolithic projects.
As such, I will surely write about Project Jigsaw again – and then with a focus on the good sides. Stay tuned if you want to read about it.
Reference: | How Java 9 And Project Jigsaw May Break Your Code from our JCG partner Nicolai Parlog at the CodeFx blog. |