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 as 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.
What does Required filename-based automodules detected. warning mean?
Automatic module recap
An explicit module (i.e. one with a module-info.java
) can only access code of modules that it requires (ignoring implied readability for a moment). That's great if all dependencies are modularized, but what if they are not? How to refer to a JAR that isn't modular?
Automatic modules are the answer: Any JAR that ends up on the module path gets turned into a module. If a JAR contains no module declaration, the module system creates an automatic module with the following properties:
- inferred name (this is the important bit here)
- reads all other modules
- exports all packages
Maven relies on that mechanism and once you create a module-info.jar
it places all dependencies on the module path.
Automatic names
There are two ways to infer an automatic module's name:
- entry in the manifest
- guess from the JAR file name
In the first case, the name was deliberately picked by the maintainer, so it can be assumed to be stable (for example it doesn't change when the project gets modularized). The second one is obviously unstable across the ecosystem - not all project setups lead to the exact same file names of their dependencies.
What does it mean?
The reason for the warnings is that some of your dependencies are automatic modules and do not define their future module name in the manifest. Instead, their name is derived from the file name, which makes them unstable.
Stable names
So why are unstable names such a problem? Assume your library gets published with requires guava
and my framework gets published with requires com.google.guava
. Now somebody uses your library with my framework and suddenly they need the modules guava and com.google.guava on their module path. There is no painless solution to that problem, so it needs to be prevented!
How? For example by discouraging developers from publishing artifacts that depend on filename-based automatic modules. /p>
Java 9, Jigsaw and automatic modules
You need to add a library entry first, to make it available under Modules
:
Step 1: Add a library (Add -> Java -> jar file)
Step 2: Select the module (remember to click "Apply")
After that, the module-info.java
file will be successfully validated:
Why Java Automatic modules do not contain exports section
I believe, the command line option --describe-module
within the jar
tool is just to describe what the jar file is about, if its an explicit module the complete descriptor is shared whie for automatic module just the name is depicted.
Quoting from the command jar --help
Print the module descriptor, or automatic module name
On the other hand, if you try using jdeps
for generating module-info.java
of an automatic module given a jar file, you can notice that such packages exports are actually present in the module declaration. Say for example:
jdeps -verbose:class --generate-module-info ../Desktop ~/.m2/repository/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar
writes to .../Desktop/org.apache.commons.lang3/module-info.java
the following
module org.apache.commons.lang3 {
requires transitive java.desktop;
exports org.apache.commons.lang3;
exports org.apache.commons.lang3.arch;
exports org.apache.commons.lang3.builder;
exports org.apache.commons.lang3.concurrent;
exports org.apache.commons.lang3.event;
exports org.apache.commons.lang3.exception;
exports org.apache.commons.lang3.math;
exports org.apache.commons.lang3.mutable;
exports org.apache.commons.lang3.reflect;
exports org.apache.commons.lang3.text;
exports org.apache.commons.lang3.text.translate;
exports org.apache.commons.lang3.time;
exports org.apache.commons.lang3.tuple;
}
Automatic Module cannot be found
Change
requires json;
to
requires org.json;
The reason for that is specified in the META-INF
of the artifact.
Automatic-Module-Name: org.json
What does a module.a binds module.b mean during the resolution?
This most likely refers to the bind operation of resolveAndBind
processing uses
—provides
relationships.
This method works exactly as specified by
resolve
except that the graph of resolved modules is augmented with modules induced by the service-use dependence relation.More specifically, the root modules are resolved as if by calling
resolve
. The resolved modules, and all modules in the parent configurations, withservice dependences
are then examined. All modules found by the given module finders thatprovide
an implementation of one or more of the service types are added to the module graph and then resolved as if by calling theresolve
method. Adding modules to the module graph may introduce new service-use dependences and so the process works iteratively until no more modules are added.
So, binding takes place after resolving, but still before any code of the involved modules has been invoked. Namely, it doesn’t matter whether the ServiceLoader
is actually used within the module(s) or not. But when it is used, it will utilize the already available information. So a lot of potential problems have been precluded at this point already. This is also the reason why we could build optimized module images pre-linking such services.
This, however, doesn’t work with automatic modules, as they don’t have uses
directives. Without that information, service lookups can only be done when an actual use of ServiceLoader
happens, just like with classes loaded through the old classpath.
Note that the issue in the linked Q&A is a bit different. According to the OP’s information, a module declaration has been used when compiling. But then, the OP ran the application using the -jar
option which puts the specified jar file on the classpath and loads it from there, creating an unnamed module, rather than an automatic module. This ignores the compiled module-info
and in absence of old-fashioned META-INF/services/…
resources, no service implementation was found at all. The OP’s code was designed to fall back to the default service implementation if none had been found, which is indistinguishable from the scenario of finding the default service through the ServiceLoader
.
The crucial differences of your answer are the start method -m base.service/base.service.ServiceUser
, which will locate the base.service
through the module path and launch its base.service.ServiceUser
, as well as --add-modules …user.service
, to ensure that the module providing the service will be added to the runtime environment. The latter is needed since there is no direct dependency from the launched module base.service
to the user.service
, so it wouldn’t be loaded automatically.
So in your answer’s setup, both modules are loaded as such. When they have a module-info
, its provides
directive will be processed to find the service implementation, otherwise, it’s an automatic module and must have a META-INF/services/…
file. As said above, there is no equivalent to the uses
directive for automatic modules, so you will never see a “binds” log entry for them. But they may still use the service lookup.
How to use 3rd party library in Java9 module?
You can use your library as an automatic module. An automatic module is a module that doesn't have a module descriptor (i.e. module-info.class
).
But what name do you need to specify to refer to an automatic module? The name of the automatic module is derived from the JAR name (unless this JAR contains an Automatic-Module-Name
attribute). The full rule is quite long (see Javadoc for ModuleFinder.of
), so for simplicity, you just have to drop the version from its name and then replace all non-alphanumeric characters with dots (.
).
For example, if you want to use foo-bar-1.2.3-SNAPSHOT.jar
, you need to add the following line to module-info.java
:
module <name> {
requires foo.bar;
}
Related Topics
Comparing Arrays in Junit Assertions, Concise Built-In Way
Java Operator Precedence Guidelines
Consider Defining a Bean of Type 'Package' in Your Configuration [Spring-Boot]
What Is the Best Way Get the Symmetric Difference Between Two Sets in Java
Hibernate Saveorupdate Behavior
How to Avoid a Lot of If Else Conditions
How to Pause and Resume a Thread in Java from Another Thread
Java: What's the Big-O Time of Declaring an Array of Size N
Recursively List All Files Within a Directory Using Nio.File.Directorystream;
How to Make a Jbutton in a Jtable Cell Click-Able
How to Avoid 'Instanceof' When Implementing Factory Design Pattern
Do Any Jvm's Jit Compilers Generate Code That Uses Vectorized Floating Point Instructions
How to Avoid 'Instanceof' When Implementing Factory Design Pattern
Is There a Newline Constant Defined in Java Like Environment.Newline in C#