We’ve been looking at Java modularity for the past few weeks. In this article I discuss the unnamed module and automatic modules.
If you’ve missed out any of the previous posts, here are the links:
- Java Modularity Part 1 – Introduction
- Java Modularity Part 2 – Keywords and Descriptors
- Java Modularity Part 3 – Requires and Exports
- Java Modularity Part 4 – Services
- Java Modularity Part 5 – Reflection
Types of Java Modules
There are four types of Java modules:
- System Modules – These are the modules listed when we run the
--list-modules
command. They include the Java SE and JDK modules. - Application Modules – These are the modules we create when we modularize our code. They are defined in the compiled module descriptor (
module-info.class
) in the JAR file. - Automatic Modules – We can include unofficial modules by adding existing JAR files to the module path. The name of the module is derived from the name of the JAR.
- Unnamed Module – When a class or JAR is loaded onto the
CLASSPATH
, but not the module path, it’s automatically added to the unnamed module. This is a catch-all module for backward compatibility with legacy Java code.
The Unnamed Module
From Java 9, all code must be placed in modules. Then how do we use legacy Java libraries? We can still use the -classpath
JVM flag. We can include all our legacy Java classes on the CLASSPATH
. All classes found on the CLASSPATH
become the members of unnamed module.
The unnamed module is similar to the default package in Java 8 and earlier. Remember the default (unnamed) package contains any classes that are not specifically placed in a package.
When we execute code that is not in a module, the code is loaded from the CLASSPATH
and placed in the unnamed module. We can run un-modularized code in the modularized JDK, but it does not get many modularization benefits.
The unnamed module is not really a module, but can be seen as the default module. If a package has not been added to a named module, then it will automatically be part of the unnamed module. We do this often when we want to run Java 8 (or earlier) programs with a Java 9 (or later) JVM without modularizing them first.
The unnamed module implicitly exports
all the types in the packages found in the JAR
file. It also reads all other modules. However, because the module is unnamed, a named module cannot use it in a requires
directive. This means that a named module cannot depend on the unnamed module. The classes in the unnamed module are only readable by other classes in the unnamed module, or by automatic modules (more on those soon).
Adding Modules to the Unnamed Module
To add the named modules to the default set of root modules, we use the JVM flag –add-modules (,)*
where is a module name.
For example to provide access to all java.net.http
modules, we would use the following flag:
--add-modules java.net.http
Automatic Modules
Let’s say we’ve modularized our code, but we use a third party library which isn’t modularized? What do we do? We’ve seen we can put the library on the CLASSPATH
. This will make it part of the unnamed module, but our named modules won’t be able to use it, because named modules can’t read classes from the unnamed module.
This is where automatic modules come into play. An automatic module is derived from a JAR
file that is not modularized, i.e. it has no module descriptor. This includes all JAR
files created with Java 8 and earlier. When we put a non-modular JAR
file on the module path (not the CLASSPATH
) the JVM converts it to an automatic module at runtime.
Important aspects of automatic modules:
- An automatic module implicitly
exports
all its packages, so all named modules on the module path can use the public types in the automatic module’s packages. - Named modules still must explicitly require the automatic module.
- An automatic module implicitly
requires
all other modules on the module path, including other automatic modules and the unnamed module. In other words, it can read all packages exported by all named modules in the module path. - If we have multiple automatic modules, each automatic module can read the classes of all other automatic modules.
- An automatic module is a named module whose name is derived from the
JAR
file name. If theJAR
file iscom-incusdata-module.jar
, then the module name will becomecom.incusdata.module
. The.jar
suffix is removed. The hyphens (-
) will be replaced with dots (.
). - If the
JAR
file has a version number, e.g.com-incusdata-module-3.1.4.jar
, then the version is also removed before the automatic module name is derived. The resulting automatic module name will still becom.incusdata.module
.
What’s Next?
I’ve just scratched the surface of the unnamed module and automatic modules. (For more information, IBM DeveloperWorks has some great articles on modularity. As does Baeldung).
In the next post, we’ll look at compiling the module declaration and packaging it into a module.
Please share your views and comments.