What is an automatic module?

I first answer your actual question (“What is an automatic module?”), but I also explain what they are there for. It is hard to understand why automatic modules behave the way they do without that information.

What is an automatic module?

The module system creates a module from every JAR it finds on the module path. For modular JARs (i.e. those with module descriptors) that is straightforward as they define the module’s properties (name, requires, exports). For plain JARs (no module descriptor) this approach doesn’t work, so what should the module system do instead? It automatically creates a module – an automatic module, so to speak – and takes the most safe guesses for the three properties.

Name

Deriving the name is a two-step process:

  • if the JAR defines the Automatic-Module-Name header in its manifest, it defines the module’s name
  • otherwise, the JAR file name is used to determine the name

The second approach is intrinsically unstable, so no modules with a dependency on such an automatic module should be published. Maven warns about that.

Requires

Since a plain JAR expresses no requires clauses, the module system lets automatic modules read all other modules that make it into the readability graph (aka module graph). Unlike explicit modules, automatic ones also read the unnamed module, which contains everything that was loaded from the class path. This seemingly minor detail turns out to be very important (see below).

Automatic modules have some further readability quirks, though:

  • As soon as the first automatic module is resolved, so are all others. That means once a single plain JAR on the module path is referenced by another module, all plain JARs are loaded as automatic modules.
  • Automatic modules imply readability on all other automatic modules, which means a module reading one of them, reads all of them.

Taken together this can have the unfortunate effect that an explicit module (i.e. a non-automatic one) that depends on several plain JARs can get away with only requiring one of them (as long as the others end up on the module path as well).

Exports/Opens

Since the JAR contains no information which packages are considered public APIs and which aren’t, the module system exports all packages and also opens them for deep reflection.

More

The module system also scans META-INF/services and makes the automatic module provide the services named therein. An automatic module is assumed allowed to use all services.

Finally, the Main-Class manifest entry is processed as well, so a plain JAR that defines one can be launched just like an automatic module where the main class was set with the jar tool (i.e. java --module-path my-app.jar --module my.app).

Proper module

Once the automatic module was created, it is treated as any other module. This explicitly includes that the module system checks it a any other module, for example for split packages.

What is an automatic module for?

One of the reasons for introducing modules was to make compiling and launching applications more reliable and find errors sooner that was possible with the class path. A critical aspect of that are requires clauses.

To keep them reliable, there is no way for a module declaration to require anything other than a named module, which excludes everything loaded from the class path. If the story ended here, a modular JAR could only depend on other modular JARs, which would force the ecosystem to modularize from the bottom up.

That is unacceptable, though, so automatic modules were introduced as a means for modular JARs to depend on non-modular ones and all you need to do for that is place the plain JAR on the module path and require it by the name the module system gives it.

The interesting bit is that because automatic modules read the unnamed module, it is feasible (and I generally recommend doing that) to leave its dependencies on the class path. This way automatic modules act as a bridge from the module to the class path.

Your modules can sit on one side, require their direct dependencies as automatic modules, and indirect dependencies can remain on the other side.
Every time one of your dependencies turns into an explicit module, it leaves the bridge on the modular side and draws its direct dependencies as automatic modules onto the bridge.

Leave a Comment