Java 9's Jigsaw Module Framework (JPMS)

Categories: Java

One of the big features for the upcoming Java version 9 is supposed to be the Jigsaw (aka Java Platform Modular System or JPMS) module framework. However it has been controversial over its whole development cycle - and now that the release is coming up, some non-Oracle groups on the advisory board are intending to vote against the release of Java 9 due to flaws in Jigsaw.

From the available info, it appears that Jigsaw has two different aims:

  • To allow Oracle to easily release subsets of the Java standard libraries for various purposes (a full JRE for desktops, a “headless” one for servers, a “minimal” one for phones and embedded purposes, etc).

  • To allow third-party library developers to use the same features to minimise conflicts between their code and other libraries in the classpath.

As I understand it, the criticism is primarily that Oracle have succeeded on the first goal, but badly failed to handle the second. It appears that Jigsaw introduces a number of changes that potentially break existing software; a runtime param has been included so a JVM can be run with Jigsaw disabled so that existing code can be used but library authors are expected to release new jigsaw-compatible versions of absolutely everything so that eventually at some future time applications can be run with Jigsaw enabled. This rather reminds me of the Python2-to-Python3 migration - which just about everyone now agrees was a bad idea.

In addition, there are serious questions about whether Jigsaw will actually work in the real world, even if every library author buys in to the new concept. After all, there is no production experience with Jigsaw - it is purely an invented-by-committee framework.

In particular, the authors of frameworks such as JEE and OSGi are rather unhappy. The concerns of a combined group of experts are presented here (as seen on slashdot).

The view of the Jigsaw team appears to be that as a new module system is being introduced, it is a good chance to deliberately not support “poor design practices”; users of Jigsaw must follow proper design principles as they are seen by the Jigsaw team. That view didn’t convince.

It will be interesting to see how this argument turns out…

UPDATE: After some compromises, the vote has passed. Java9 will be coming, and will have JPMS (Jigsaw) in almost its original form - but the “backwards compatibility” mode will be enabled by default, so existing apps doing reflection won’t fail. The lead architect for the JPMS component is still convinced his “break the world” approach is right, and wants the flag to be turned on in Java 10. I wonder if he actually develops software in the real world…

To summarize the linked articles (hopefully correctly): when JPMS (Java Platform Modular System) is enabled, the standard reflection APIs work differently than in previous releases. In particular, there are many operations that work with JPMS disabled, but return different results or simply throw an exception with JPMS enabled.

This change means that a java application which has been working for years may successfully start on a JPMS-enabled JVM but then throw an exception at some later time when performing an operation which used to work. The “later time” might occur only in specific and potentially rare conditions. Particularly problematic code for JPMS are things like serialization/deserialization, object-relational mapping frameworks, proxying frameworks, dependency-injection, instantiation-via-reflection, supporting pluggable extensions, custom classloaders, use of the thread-context-classloader, the ServiceLoader feature, and anything else which relies heavily on reflection. That shows why the JEE teams in particular have concerns with JPMS - JEE does a lot of that sort of stuff.

In my opinion, this change to runtime behaviour is just plain nasty. It’s not a guaranteed-failure-on-startup, where the user will immediately notice the problem and can restart the app with JPMS disabled, but instead a “maybe crash later” problem which may not be easily traceable back to having JPMS enabled.

Given this, the original plan to have JPMS behaviour enabled by default in Java9 is IMO just unreasonable.

The compromise made by the Oracle Java team to get the Java9 vote approved was primarily to make the new JPMS behaviour default to off, ie for “backwards compatibility mode” to be enabled by default. That at least allows the arguments over JPMS to continue in the background while we get access to some of the other Java9 features without breaking existing code. Thanks to RedHat, IBM and others who fought for this.

The lead for the JPMS project is still clearly keen on his “break the world” approach and has stated he expects/wants JPMS behaviour to be enabled-by-default in the next Java release. At least defaulting it to off for Java9 gives everyone a year or so to actually get some experience with JPMS (via enabling it in testing environments) before the next version of Java comes out. Given that this is effectively a design-by-committee feature that has never been used in the real world (compared for example to migrating existing functionality from an external library into Java core), some real-world feedback seems like a really good idea.

I’m still personally not convinced that the world will bother testing/updating every existing Java library to be JPMS-compatible, ie in 10 years time there will still be IMO many critical libs which are not useable under JPMS. And as JPMS is a whole-jvm feature rather than a per-lib feature, ie no app can be used with JPMS enabled unless every lib that it uses is JPMS-compatible, that means that JPMS modular behaviour will not be usable in the real world for a very very long time, if ever.

Note that Java’s SDK classes are now JPMS-compatible, ie all the standard tests for the Java SDK pass when JPMS is turned on. That allows the Java release team to be sure that there are no unexpected/hidden dependencies between different subsets of the SDK, and thus allows them to safely create SDK releases which are subsets of the full SDK without worrying about anything going boom at runtime. Whether JPMS is actually turned on at runtime or not is a different issue.

I suspect history is repeating itself here. When the Java team decided to build a standard logging framework for the SDK, there were already existing successful libraries eg log4j and slf4j. However rather than just integrate proven code into the SDK, they invented their own solution - which is flawed and 10 years later is still not widely used. For modularity, there is a proven solution with OSGi which I personally find very elegant. However again the Java maintainers are inventing their own solution. I expect the outcome will be the same again.