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.
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.
Deriving the name is a two-step process:
Automatic-Module-Name
header in its manifest, it defines the module's nameThe second approach is intrinsically unstable, so no modules with a dependency on such an automatic module should be published. Maven warns about that.
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:
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).
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.
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
).
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.
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.