What is an automatic module?
Automatic modules are mentioned many times on stackoverflow but I couldn't find a complete, succinct and self-sufficient definition of an automatic module.
So, what is an automatic module? Does it export all packages? Does it open all packages? Does it read all other modules?
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.
An automatic module is a named module that is defined implicitly, since it does not have a module declaration. An ordinary named module, by contrast, is defined explicitly, with a module declaration; we will henceforth refer to those as explicit modules.
The primary benefit of using these is that they allow you to treat an artifact as a module when compiling or running without waiting for it to be migrated to the modular structure.
The module name of an automatic module is derived from the JAR file used to include the artifact if it has the attribute Automatic-Module-Name in its main manifest entry. The module name is otherwise derived from the name of the JAR file by the ModuleFinder
.
Derived from the fact that the automatic module doesn't have a module declaration it's practically not feasible to tell what all modules or packages does it reads, opens or exports.
➜ So, since there are no explicit exports/opens for packages residing in the automatic module, described as -
.. no practical way to tell which of the packages in an automatic module are intended for use by other modules, or by classes still on the class path. Every package in an automatic module is, therefore, considered to be exported even if it might actually be intended only for internal use.
➜ Quoting the link further -
... no practical way to tell, in advance, which other modules an automatic module might depend upon. After a module graph is resolved, therefore, an automatic module is made to read every other named module, whether automatic or explicit.
The one of the proposals - An automatic module offers the traditional level of encapsulation: All packages are both open for deep reflective access and exported for ordinary compile-time and run-time access to their public types.
➜ Additionally, an automatic module
grants implied readability to all other automatic modules
due to the reason, that while using multiple automatic modules in a module its
..not feasible to determine whether one of the exported packages in an automatic module(x.y.z) contains a type whose signature refers to a type defined in some other automatic module(a.b.c).