What’s The Problem With Automatic Modules?

To answer that question in the space of a newsletter, I have to assume a basic understanding of how the module system works, particularly the concepts of modular JARs, the module path, and dependency resolution according to requires clauses. If you have no idea what I am talking about or would like a refresher, have a look at this hands-on guide to the module system.

I'll wait...

Independent Migration

Great, you’re back! :) So you know about organizing an application into multiple modules and how to code, compile, and launch that. But unless your application has no dependencies, that’s not quite going to cut it, right? I mean, do you have to wait with creating modules for your application until all your dependencies are modularized?

Fortunately, the answer is no. You can modularize your framework, library, or application even though your dependencies are still regular JARs. This is in fact a key feature of the module system because it allows every project to modularize itself independently of what happens downstream and upstream.

So how do you express your dependency on unmodularized artifacts? (Because you have to do that for their types to be accessible.) You can not simply put them on the class path because you can not establish a dependency to its content. (This is not a technical limitation, it was deliberately decided to keep modules away from “the chaos of the class path”.)

So, again, how do you use those types then? This is where automatic modules come in. Turns out you can put regular JARs on the module path and the module system will give it a name and export all its types — automatically. Then your shiny modules can depend on those JARs in modular disguise. And this is where the trouble begins.

Deadly Diamond Of Death

Because to depend on a module, you have to know its name and bake it into your module descriptor. An automatic module’s name is determined based on its file name and that is not exactly the most stable property. In fact, it is entirely possible that different build processes will give the same file different names.

Given the enormous size if the Java ecosystem, this makes it likely that sooner or later different projects will use the same unmodularized artifact under different names. And as soon as you depend on two of these projects, your application is doomed:

Your application depends on module lib, which depends on the project “Mango” but knows it as automatic module anacardiaceae.mangifera. The application also depends on framework, which also depends on “Mango” but knows it as juicy.drupe. Now you depend on two “different” modules, namely anacardiaceae.mangifera and juicy.drupe that export the same API.

Since no two modules must contain the same packages (preventing you from using two artifacts) and no module can stand in for another (preventing you from using just one under two names), there is no configuration that can fulfill these dependencies. The module system will not let you compile or launch such this application. It just created its particular variant of the deadly diamond of death…

What Now?

Yes, what now? Good question. First of all, it is entirely unpredictable how often this problem will actually occur in practice. But given the exactly zero options you have to solve it, should it ever occur, this is not too reassuring.

The discussions on the Jigsaw mailing lists (1, 2) came up with a couple of ideas:

use the pom.properties file that is present in 95% of the artifacts on Maven Central to deduce the module name groupId.artifactId

file that is present in 95% of the artifacts on Maven Central to deduce the module name allow module aliasing

drop automatic modules (and let modules depend on the class path content?)

So far the JDK team did not respond to any of them but I’m positive that they will in due time.