Project Jigsaw has ambitious objectives, one of them is "to escape the 'JAR hell' of the brittle and error-prone class-path mechanism". But while it will achieve many of its goals it looks like it may fall short on this one.
So will there be module hell instead?
To know what we are talking about we'll start with a quick recap of JAR hell. We will then discuss what aspects Jigsaw touches on and how that might not change the big picture. Lastly we will have a look at the official stance on the topic and formulate a proposal to prevent looming module hell.
I discussed JAR hell in detail in my last post, which you might want to read if you haven't already. It ends with this list of the different circles of JAR hell:
- unexpressed and transitive dependencies
- version conflicts
- complex class loading
Based on what build tools and component systems (called containers by the JDK developers) bring to the game and how widely they are used it concludes that unexpressed and transitive dependencies are largely solved, shadowing at least eased and complex class loading not commonplace.
This leaves version conflicts as the most problematic aspect of JAR hell, influencing everyday update decisions in many, many projects.
▚What Will Change With Jigsaw?
I have already written about all the features Project Jigsaw was planned to bring to Java 9 but this post will take a different angle. First, it is influenced by experiments with the current early access build and, second, it only looks at the aspects pertaining JAR/module hell.
The core concept Jigsaw brings to Java are modules. Overly simplified, a module is like a JAR with some additional information and features. Some of those pieces of information are a module's name and the names of other modules it depends on.
The information is interpreted by the compiler and the JVM when they process a module. Tasked to compile or launch one, they will transitively resolve all dependencies within a universe of modules specified via the module path. Roughly said, this is analogue to a class path scan but now we are looking for entire modules instead of individual classes and, in case of the JVM, we are doing it at launch-time not at runtime.
Resolving the transitive dependencies of a module fails with an error if not all modules are found on the module path. This clearly solves the problem of unexpressed and endlessly transitive dependencies.
Jigsaw solves the problem of unexpressed and endlessly transitive dependencies.
I see it as a material benefit that the Java language now officially knows about dependencies and that all the tools, starting with the compiler and JVM, understand and work with them! This should not be understated.
But I assume it will have little effect on the typical developer's everyday work since this is already sufficiently addressed by existing infrastructure, i.e. the build tool.
This becomes even clearer when we consider where the module information will come from.
It already exists as part of the build information, e.g. in the
It would be redundant to additionally specify names and dependencies for the module system and it is hence assumed that the build tool will use its information to automatically generate the module information.
(I am sure Mark Reinhold or Alan Bateman repeatedly stated this but can't find a quote right now.
Store this as hearsay for now.)
Jigsaw eliminates the problem of shadowing:
The module system ensures that every dependence is fulfilled by precisely one other module, [...] that every module reads at most one module defining a given package, and that modules defining identically-named packages do not interfere with each other.
To be more precise, the module system quits and reports an error as soon as it encounters ambiguous situations, e.g. two modules exporting the same package to the same module.
We identified conflicting versions of third party libraries as the most daunting aspect of JAR hell. The most straight forward solution would be a module system able to load different versions of the same module. It would have to prove that these versions can not interact but given the strong promises regarding encapsulation and readability it looks like it should be able to do that.
Now, here is the problem:
It is not necessary to support more than one version of a module within a single configuration.
Indeed the current build neither creates nor understands module version information.
For some time it looked like there would be workarounds. The ugliest but most promising one renames the conflicting artifacts so that they are no longer two different versions of the same module but appear as two different modules, coincidently exporting the same packages.
But this approach fails. Apparently ensuring "that modules defining identically-named packages do not interfere with each other" is solved by roundly rejecting any launch configuration where two modules export the same packages. Even if no module would read them both!
Jigsaw does nothing to help with the problem of conflicting versions.
So apparently Jigsaw does nothing to help with the problem of conflicting versions unless one resorts to component-system-like behavior at runtime. What a disappointment!