Current Tutorial
Extending the Module Graph with --add-modules and --add-reads
That's the end of the series!

Extending the Module Graph with --add-modules and --add-reads

Starting with an initial set of root modules, the module system computes all of their dependencies and builds a graph, where the modules are nodes and their readability relations are directed edges. This module graph can be extended with the command line flags --add-modules and --add-reads, which add modules (and their dependencies) and readability edges, respectively. The former has a few use cases, the latter is very niche, but either way, it's good to know them.

Note: You need to know the module system basics and how to build and launch from the command line to get the most out of this article.

Adding Root Modules with --add-modules

The option --add-modules $MODULES, which is available on javac, jlink, and java and accepts a comma-separated list of modules, adds them to the set of root modules. (Root modules form the initial set of modules from which module resolution starts.) This allows you to add modules (and their dependencies) to the module graph that would otherwise not show up because the initial module does not depend on them (directly or indirectly).

The --add-modules option has three special values:

  • ALL-DEFAULT is the set of modules that is picked as root modules when launching code from the class path. This is useful when the application is a container that hosts other applications which can, in turn, depend upon modules not required by the container itself.
  • ALL-SYSTEM adds all system modules to the root set, which is sometimes needed by test harnesses. This option will cause many modules to be resolved; in general, ALL-DEFAULT should be preferred.
  • ALL-MODULE-PATH adds all modules found on the module path to the root set. This is provided for use by build tools such as Maven, which already ensure that all modules on the module path are needed. It is also a convenient means to add automatic modules to the root set.

The first two only work at run time and are used for very specific cases that this article does not discuss. The last one can be quite useful, though: With it, all modules on the module path become root modules and hence all of them make it into the module graph.

The space after --add-modules can be replaced with an equal sign =, which helps with some tool configurations: --add-modules=....

Use Cases for Adding Modules

One use case for --add-modules is adding optional dependencies that are not otherwise required and would thus not make it into the module graph. As an example, let's imagine a project that has an optional dependency on java.sql, but the module is not otherwise required:

# launch without java.sql
$ java
    --module-path example.jar:deps
    --module com.example/com.example.Main

# launch with java.sql
$ java
    --module-path example.jar:deps
    --add-modules java.sql
    --module com.example/com.example.Main

Another is to define the set of root modules when creating runtime images with jlink.

When adding modules it might be necessary to let other modules read them, so let's do that next.

Adding Readability Edges with --add-reads

The compiler and runtime option --add-reads $MODULE=$TARGETS adds readability edges from $MODULE to all modules in the comma-separated list $TARGETS. This allows $MODULE to access all public types in packages exported by those modules even though $MODULE has no requires clauses mentioning them. If $TARGETS is set to ALL-UNNAMED, $MODULE can even read the unnamed module.

The space after --add-reads can be replaced with an equal sign =, which helps with some tool configurations: --add-reads=.../....

Example for Adding Readability

Let's return to the example before, where code used java.sql, but didn't want to always depend on it. An alternative approach to optional dependencies would be to not list the dependency at all and only add it with --add-modules and --add-reads (this is rarely helpful and not generally recommended - just an example):

# this only shows launch, but compilation
# would also need the two options
$ java
    --module-path example.jar:deps
    --add-modules java.sql
    --add-reads com.example=java.sql
    --module com.example/com.example.Main

Last update: September 14, 2021


Current Tutorial
Extending the Module Graph with --add-modules and --add-reads
That's the end of the series!