Introducing Modules
The Java Platform Module System includes the following:
A module is a group of one or more packages plus a special file called module-info.java.
dependencies where one module relies on code in another.
Java Platform Module System (JPMS)
BENEFITS OF MODULES
jlink is used to create this runtime image.module-info.java
This is the simplest possible module-info.java file
module zoo.animal.feeding {
}1: module zoo.animal.care {
2: exports zoo.animal.care.medical;
3: requires zoo.animal.feeding;
4: }There are a few key differences between a module-info file and a regular Java class:
module-info file must be in the root directory of your module. Regular Java classes should be in packages.module-info file must use the keyword module instead of class, interface, or enum.That’s a lot of rules for the simplest possible file. There will be many more rules when we flesh out this file later in the chapter.
CAN A MODULE-INFO.JAVA FILE BE EMPTY?
Yes. As a bit of trivia,
it was legal to compile any empty file with a .java extension even before modules.
The compiler sees there isn’t a class in there and exits without creating a .class file.
COMPILING OUR FIRST MODULE
> [!NOTE]
When you’re entering commands at the command line, they should be typed all on one line.
javac --module-path mods -d feeding feeding/zoo/animal/feeding/*.java feeding/module-info.java
-d option specifies the directory to place the class files in.--module-path option indicates the location of any custom module files.--module-path and -p are equivalent.The following four commands show the -p option:
javac -p mods -d feeding feeding/zoo/animal/feeding/*.java feeding/*.java javac -p mods -d feeding feeding/zoo/animal/feeding/*.java feeding/module-info.java javac -p mods -d feeding feeding/zoo/animal/feeding/Task.java feeding/module-info.java javac -p mods -d feeding feeding/zoo/animal/feeding/Task.java feeding/*.java
WHAT HAPPENED TO THE CLASSPATH?
You can still use these options in Java 11. In fact, it is common to do so when writing nonmodular programs.
-cp, --class-path, and -classpath
RUNNING OUR FIRST MODULE
Pay special attention to the book.module/com.sybex.OCP part. It is important to remember that you specify the module name followed by a slash (/) followed by the fully qualified class name.
java --module-path mods --module book.module/com.sybex.OCP
--module-path, -p--module, -mexamples:
java --module-path feeding --module zoo.animal.feeding/zoo.animal.feeding.Task java -p feeding -m zoo.animal.feeding/zoo.animal.feeding.Task
PACKAGING OUR FIRST MODULE
Be sure to create a mods directory before running this command:
jar -cvf mods/zoo.animal.feeding.jar -C feeding/ .
run the program again, but this time using the mods directory instead of the loose classes:
java -p mods -m zoo.animal.feeding/zoo.animal.feeding.Task
Since the module path is used, a module JAR is being run.
> [!NOTE]
It is possible to version your module using the –module-version option.
This isn’t on the exam but is good to do when you are ready to share your module with others.
version your module using the –module-version option.
ORDER MATTERS!
Order matters when compiling a module.
javac -p mods -d care care/module-info.java care/zoo/animal/care/details/*.java care/zoo/animal/care/medical/*.java
The compiler complains that it doesn’t know anything about the package zoo.animal.care.medical.
care/module-info.java:3: error: package is empty or does not exist: zoo.animal.care.medical exports zoo.animal.care.medical;
jar -cvf mods/zoo.animal.care.jar -C care/ .
Diving into the module-info File
These are not Java keywords they are directives, can appear in any order in the module-info file.
EXPORTS
module zoo.animal.talks {
exports zoo.animal.talks.content to zoo.staff;
exports zoo.animal.talks.media;
exports zoo.animal.talks.schedule;
requires zoo.animal.feeding;
requires zoo.animal.care;
}EXPORTED TYPES
Exporting a package
REQUIRES TRANSITIVE
requires moduleName specifies that the current module depends on moduleName.
There’s also a requires transitive moduleName, which means that any module that requires this module will also depend on moduleName.
module zoo.animal.feeding {
exports zoo.animal.feeding;
}
module zoo.animal.care {
exports zoo.animal.care.medical;
requires transitive zoo.animal.feeding;
}
module zoo.animal.talks {
exports zoo.animal.talks.content to zoo.staff;
exports zoo.animal.talks.media;
exports zoo.animal.talks.schedule;
// no longer needed requires zoo.animal.feeding;
// no longer needed requires zoo.animal.care;
requires transitive zoo.animal.care;
}
module zoo.staff {
// no longer needed requires zoo.animal.feeding;
// no longer needed requires zoo.animal.care;
requires zoo.animal.talks;
}Duplicate requires Statements
module bad.module {
requires zoo.animal.talks;
requires transitive zoo.animal.talks;
}Java doesn’t allow you to repeat the same module in a requires clause. It is redundant and most like an error in coding. Keep in mind that requires transitive is like requires plus some extra behavior.
PROVIDES, USES, AND OPENS
The provides keyword specifies that a class provides an implementation of a service.
To use it, you supply the API and class name that implements the API:
provides zoo.staff.ZooApi with zoo.staff.ZooImpl
The uses keyword specifies that a module is relying on a service. To code it, you supply the API you want to call:
uses zoo.staff.ZooApi
Discovering Modules
java -p mods -d zoo.animal.feeding java -p mods --describe-module zoo.animal.feeding
jar -f mods/zoo.animal.feeding.jar -d jar --file mods/zoo.animal.feeding.jar --describe-module
Discovering Modules via java command
module-info in zoo.animal.feeding:
module zoo.animal.feeding {
exports zoo.animal.feeding;
}The java command now has an option to describe a module. The following two commands are equivalent:
java -p mods -d zoo.animal.feeding java -p mods --describe-module zoo.animal.feeding
Each prints information about the module. For example, it might print this:
zoo.animal.feeding file:///absolutePath/mods/zoo.animal.feeding.jar exports zoo.animal.feeding requires java.base mandated
MORE ABOUT DESCRIBING MODULES
module-info in zoo.animal.care:
module zoo.animal.care {
exports zoo.animal.care.medical to zoo.staff;
requires transitive zoo.animal.feeding;
}Now we have the command to describe the module and the output.
java -p mods -d zoo.animal.care zoo.animal.care file:///absolutePath/mods/zoo.animal.care.jar requires zoo.animal.feeding transitive requires java.base mandated qualified exports zoo.animal.care.medical to zoo.staff contains zoo.animal.care.details
Listing Available Modules
you can use the java command to list the modules that are available. The simplest form lists the modules that are part of the JDK:
java --list-modules
When we ran it, the output went on for 70 lines and looked like this:
java.base@11.0.2 java.compiler@11.0.2 java.datatransfer@11.0.2
This is a listing of all the modules that come with Java and their version numbers. You can tell that we were using Java 11.0.2 when testing this example.
java -p mods --list-modules
zoo.animal.care file:///absolutePath/mods/zoo.animal.care.jar zoo.animal.feeding file:///absolutePath/mods/zoo.animal.feeding.jar zoo.animal.talks file:///absolutePath/mods/zoo.animal.talks.jar zoo.staff file:///absolutePath/mods/zoo.staff.jar
Since these are custom modules, we get a location on the file system. If the project had a module version number, it would have both the version number and the file system path.
> [!Note]
that –list-modules exits as soon as it prints the observable modules.
It does not run the program.
Showing Module Resolution
java --show-module-resolution -p feeding -m zoo.animal.feeding/zoo.animal.feeding.Task
Luckily you don’t need to understand this output. That said, having seen it will make it easier to remember. Here’s a snippet of the output:
root zoo.animal.feeding file:///absolutePath/feeding/ java.base binds java.desktop jrt:/java.desktop java.base binds jdk.jartool jrt:/jdk.jartool ... jdk.security.auth requires java.naming jrt:/java.naming jdk.security.auth requires java.security.jgss jrt:/java.security.jgss ... All fed!
THE JAR COMMAND
the jar command can describe a module. Both of these commands are equivalent:
jar -f mods/zoo.animal.feeding.jar -d jar --file mods/zoo.animal.feeding.jar --describe-module
The output is slightly different from when we used the java command to describe the module. With jar, it outputs the following:
zoo.animal.feeding jar:file:///absolutePath/mods/zoo.animal.feeding.jar /!module-info.class exports zoo.animal.feeding requires java.base mandated
The JAR version includes the module-info in the filename, which is not a particularly significant difference in the scheme of things. You don’t need to know this difference. You do need to know that both commands can describe a module.