Implement the Java Platform Module System, as specified by JSR 376, together with related JDK-specific changes and enhancements.
The Java Platform Module System (JSR 376) proposes changes and
extensions to the Java programming language, the Java virtual machine,
and the standard Java APIs. This JEP will implement that specification.
As a consequence, the javac
compiler, the HotSpot virtual machine, and
the run-time libraries will implement modules as a fundamental new kind
of Java program component and provide for the reliable configuration and
strong encapsulation of modules in all phases of development.
This JEP will also change, extend, and add JDK-specific tools and APIs,
which are outside the scope of the JSR, that are related to compilation,
linking, and execution. Related changes to other tools and APIs, e.g.,
the javadoc
tool and the Doclet API, will be the subject of separate
JEPs.
This JEP assumes that the reader is familiar with the latest State of the Module System document and also the earlierother Project Jigsaw JEPs:
To the familiar phases of compile time (the javac
command) and run time
(the java
run-time launcher) we add the notion of link time, an
optional phase between the two in which a set of modules can be assembled
and optimized into a custom run-time image. The linking tool, jlink
,
is the subject of JEP 282; it is mentioned here because many of the new command-line options
implemented by javac
and java
are also implemented by jlink
.
The javac
, jlink
, and java
commands, as well as several others, now
accept options to specify various module paths. A module
path is a sequence, each element of which is either a module definition
or a directory containing module definitions. Each module definition is
either
A module artifact, i.e., a modular JAR file or a JMOD file containing a compiled module definition, or else
An exploded-module directory whose name is, by convention, the module's name and whose content is an "exploded" directory tree corresponding to a package hierarchy.
In the latter case the directory tree can be a compiled module
definition, populated with individual class and resource files and a
module-info.class
file at the root or, at compile time, a source module
definition, populated with individual source files and a
module-info.java
file at the root.
A module path, like other kinds of paths, is specified by a string of
path names separated by the host platform's path-separator character
(':'
on most platforms, ';'
on Windows).
Module paths are very different from class paths: Class paths are a means to locate definitions of individual types and resources, whereas module paths are a means to locate definitions of whole modules. Each element of a class path is a container of type and resource definitions, i.e., either a JAR file or an exploded, package-hierarchical directory tree. Each element of a module path, by contrast, is a module definition or a directory which each element in the directory is a module definition, i.e., a container of type and resource definitions, i.e., either a modular JAR file, a JMOD file, or an exploded module directory.
During the resolution process the module system locates a module by searching along several different paths, dependent upon the phase, and also by searching the compiled modules built-in to the environment, in the following order:
The compilation module path (specified by the command-line option
-modulesourcepath
) contains module definitions in source form
(compile time only).
The upgrade module path (-upgrademodulepath
) contains compiled
definitions of modules intended to be used in place of upgradeable
modules built-in to the environment (compile time and run time).
The system modules are the compiled modules built-in to the
environment (compile time and run time). These typically include
Java SE and JDK modules but, in the case of a custom linked
image, can also include library and application modules. At compile
time the system modules can be overridden via the -system
option,
which specifies a JDK image from which to load system modules.
The application module path (-modulepath
, or -mp
for short)
contains compiled definitions of library and application modules (all
phases). At link time this path can also contain Java SE and JDK
modules.
The module definitions present on these paths, together with the system modules, define the universe of observable modules.
When searching a module path for a module of a particular name, the module system takes the first definition of a module of that name. Version strings, if present, are ignored; if an element of a module path contains definitions of multiple modules with the same name then resolution fails and the compiler, linker, or virtual machine will report an error and exit. It is the responsibility of build tools and container applications to configure module paths so as to avoid version conflicts; it is not a goal of the module system to address the version-selection problem.
When the compiler compiles code in the unnamed module, or the java
launcher is invoked and the main class of the application is loaded from
the class path into the unnamed module of the application class loader,
then the default set of root modules for the unnamed module is computed
as follows:
The java.se
module is a root, if it exists. If it does not exist
then every java.*
module on the upgrade module path andor among the
system modules that exports at least one package, without
qualification, is a root.
Every non-java.*
module on the upgrade module path andor among the
system modules that exports at least one package, without
qualification, is also a root.
Otherwise, the default set of root modules depends upon the phase:
At compile time it is usually the set of modules being compiled (more on this below);
At link time it is empty; and
At run time it is the application's main module, as specified via the
-m
launcher option.
It is occasionally necessary to add modules to the default root set in order to ensure that specific platform, library, or service-provider modules will be present in the module graph. In any phase the option
-addmods <module>(,<module>)*
where <module>
is a module name, adds the named modules to the default
set of root modules.
As a special case at run time, if <module>
is ALL-SYSTEMDEFAULT
then all
systemthe
default set of root modules are for the unnamed module, as defined above, is
added to the root set. 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.
As a further special case at run time, if <module>
is ALL-SYSTEM
then
all system modules are added to the root set, whether or not they are in
the default set. This is sometimes needed by test harnesses. This
option will cause many modules to be resolved; in general, ALL-DEFAULT
should be preferred.
As a final special case, if <module>
is ALL-MODULE-PATH
then all
observable modules found on the relevant module paths are added to the
root set. ALL-MODULE-PATH
is valid at both compile time when compiling classes in the
unnamedand run time.
This is provided for use by build tools such as Maven, which already
ensure that all modules on the module, and at run time when the main class of the application is
loaded from the class path into the unnamed moduleare needed. It is also a
convenient means to add automatic modules to the root set.
It is sometimes useful to limit the observable modules for, e.g.,
debugging, or to reduce the number of modules resolved when the main
module is the unnamed module defined by the application class loader for
the class path. The -limitmods
option can be used, in any phase, to do
this. Its syntax is:
-limitmods <module>(,<module>)*
where <module>
is a module name. The effect of this option is to limit
the observable modules to those in the transitive closure of the named
modules plus the main module, if any, plus any further modules specified
via the -addmods
option.
(The transitive closure computed for the interpretation of the
-limitmods
option is a temporary result, used only to compute the
limited set of observable modules. The resolver will be invoked again
in order to compute the actual module graph.)
When testing and debugging it is sometimes necessary to arrange for one
module to read some other module, even though the first module does not
depend upon the second via a requires
clause in its module declaration.
This may be needed, e.g., in order for a module under test to access
the test harness itself, or to access libraries related to the harness.
The -XaddReads
option can be used, at both compile time and run time,
to do this. Its syntax is:
-XaddReads:<source-module>=<target-module>
where <source-module>
and <target-module>
are module names.
The -XaddReads
option can be used more than once, but at most once for
any particular. The effect of each
instance is to add a readability edge from the source module
to the target module. The effect of each instance is to add a
readability edge from the source module to the target module.
This is, essentially, a command-line form of a
requires
clause in a module declaration, or an invocation of an
unrestricted form of the Module::addReads
method. As a
consequence, code in the source module will be able to access types in
packages of the target module so long as each package is exported via an
exports
clause in the source module's declaration, an invocation of the
Module::addExports
method, or an instance of the
-XaddExports
option (defined below).
If, for example, a test harness injects a white-box test class into the
java.management
module, and that class extends an exported utility
class in the (hypothetical) testng
module, then the access it requires
can be granted via the option
-XaddReads:java.management=testng
As a special case, if the <target-module>
is ALL-UNNAMED
then
readability edges will be added from the source module to all present and
future unnamed modules, including that corresponding to the class path.
This allows code in modules to be tested by test frameworks that have
not, themselves, yet been converted to modular form.
It is sometimes necessary to violate the access-control boundaries
defined by the module system, and enforced by the compiler and virtual
machine, in order to allow one module to access some of the unexported
types of another module. This may be desirable in order to, e.g.,
enable white-box testing of internal types, or to expose unsupported
internal APIs to code that has come to depend upon them. The
-XaddExports
option can be used, at both compile time and run time, to
do this. Its syntax is:
-XaddExports:<source-module>/<package>=<target-module>(,<target-module>)*
where <source-module>
and <target-module>
are module names and
<package>
is the name of a package.
The -XaddExports
option can be used more than once, but at most once for
any particular combination of source module and package name. The effect
of each instance is to add a qualified export of the named
package from the source module to the target module. This is,
essentially, a command-line form of an exports
clause in a module
declaration, or an invocation of an unrestricted form of the
Module::addExports
method. As a consequence, code in
the target module will be able to access types in the named package of
the source module if the target module reads the source module, either
via a requires
clause in its module declaration, an invocation of the
Module::addReads
method, or an instance of the -XaddReads
option.
If, for example, the module jmx.wbtest
contains a white-box test for
the unexported com.sun.jmx.remote.internal
package of the
java.management
module, then the access it requires can be granted via
the option
-XaddExports:java.management/com.sun.jmx.remote.internal=jmx.wbtest
As a special case, if the <target-module>
is ALL-UNNAMED
then the
source package will be exported to all unnamed modules, whether they
exist initially or are created later on. Thus access to the
sun.management
package of the java.management
module can be granted
to all code on the class path via the option
-XaddExports:java.management/sun.management=ALL-UNNAMED
The
-XaddExports
option must be used with great care. You can use it to gain access to an internal API of a library module, or even of the JDK itself, but you do so at your own risk: If that internal API changes or is removed then your library or application will fail.
When testing and debugging it is sometimes useful to replace selected
class files or resources of specific modules with alternate or
experimental versions, or to provide entirely new class files, resources,
and even packages. This can be done via the -Xpatch
option, at both
compile time and run time. Its syntax is:
-Xpatch:<module>=<file>(<pathsep><file>)*
where <module>
is a module name, <file>
is the filesystem path name
of a module definition, and <pathsep>
is the host platform's
path-separator character.
The -Xpatch
option can be used more than once, but at most once for any
particular module name. The effect of each instance is to change how the
module system searches for a type in the specified module. Before it
checks the actual module, whether part of the system or defined on a
module path, it first checks, in order, each module definition specified
to the option. A patch path names a sequence of module definitions but
it is not a module path, since it has with "leaky," class-path-like semantics.
This allows a test harness, e.g., to inject multiple tests into the
same package without having to copy all of the tests into a single
directory.
The -Xpatch
option cannot be used to replace module-info.class
files.
If a module-info.class
file is found in a module definition on a patch
path then a warning will be issued and the file will be ignored.
If a package found in a module definition on a patch path is not already
exported by that module then it will, still, not be exported. It can be
exported explicitly via either the reflection API or the -XaddExports
option.
The -Xpatch
option replaces the -Xbootclasspath:/p
option, which has
been removed (see below).
The
-Xpatch
option is intended only for testing and debugging.
Its use in production settings is strongly discouraged.
The javac
compiler implements the options described above, as
applicable to compile time: -modulesourcepath
, -upgrademodulepath
,
-system
, -modulepath
, -addmods
, -limitmods
, -XaddReads
,
-XaddExports
, and -Xpatch
.
The compiler operates in one of three modes, each of which implements additional options.
-source
, -target
, and -release
options, is less than or
equal to 8. None of the modular options described above may be used.In legacy mode the compiler behaves in essentially the same way as it does in JDK 8.
-modulesourcepath
option is not used. The other
modular options described above may be used; the existing options
-bootclasspath
, -Xbootclasspath
, -extdirs
, -endorseddirs
, and
-XXuserPathsFirst
may not be used.Single-module mode is used to compile code organized in a traditional package-hierarchical directory tree. It is the natural replacement for simple uses of legacy mode of the form
$ javac -d classes -classpath classes -sourcepath src Foo.java
If a module descriptor in the form of a module-info.java
or
module-info.class
file is specified on the command line, or is found on
the source path or the class path, then source files will be compiled as
members of the module named by that descriptor and that module will be
the sole root module. Otherwise if the -Xmodule:<module>
option is
present then source files will be compiled as members of <module>
,
which will be the root module. Otherwise source files will be compiled
as members of the unnamed module, and the root modules will be computed
as described above.
It is possible to put arbitrary classes and JAR files on the class path in this mode, but that is not recommended since it amounts to treating those classes and JAR files as part of the module being compiled.
-modulesourcepath
option is used. The existing
-d
option to name the output directory must also be used; the other
modular options described above may be used; the existing options
-bootclasspath
, -Xbootclasspath
, -extdirs
, -endorseddirs
, and
-XXuserPathsFirst
may not be used.Multi-module mode is used to compile one or more modules, whose source code is laid out in exploded-module directories on the module source path. In this mode the module membership of a type is determined by the position of its source file in the module source path, so each source file specified on the command line must exist within an element of that path. The set of root modules is the set of modules for which at least one source file is specified.
In contrast to the other modes, in this mode an output directory must be
specified via the -d
option. The output directory will be structured
as an element of a module path, i.e., it will contain exploded-module
directories which themselves contain class and resource files. If the
compiler finds a module on the module source path but cannot find the
source file for some type in that module then it will search the output
directory for the corresponding class file.
In large systems the source code for a particular module may be spread
across several different directories. In the JDK itself,
e.g., the source files for a module may be found in any one of the
directories src/<module>/share/classes
, src/<module>/<os>/classes
, or
build/gensrc/<module>
, where <os>
is the name of the target operating
system. To express this in a module source path while preserving module
identities we allow each element of such a path to use braces ({
and
}
) to enclose commas-separated lists of alternatives and a single
asterisk (*
) to stand for the module name. The module source path for
the JDK can then be written as
{src/*/{share,<os>}/classes,build/gensrc/*}
The jar
tool can be used without change to create
modular JAR files, since a modular JAR file is just a JAR
file with a module-info.class
file in its root directory.
The jar
tool implements the following new options to allow the
insertion of additional information into module descriptors as modules
are packaged:
--main-class=<class-name>
, or -e <class-name>
for short, causes
<class-name>
to be recorded in the module-info.class
file as the
class containing the module's public static void main
entry point.
(This is not a new option; it already records the main class in the
JAR file's manifest.)
--module-version=<version>
causes <version>
to be recorded in the
module-info.class
file as the module's version string.
--hash-dependenciesmodules=<pattern>
causes hashes of the content of the
specific modules that depend upon which this module depends, in a particular set of
observable modules, to be recorded in the module-info.class
file
for later use in the validation of dependencies. Hashes are only
recorded for modules whose names match the regular expression
<pattern>
. If this option is used then the --modulepath
option
must also be used to specify the set of observable modules for the
purpose of computing the dependencies ofmodules that depend upon this module.
Additionally, the new --print-module-descriptor
option, or -p
for
short, will display the module descriptor, if any, of an existing JAR
file.
The jar
tool's --help
option can be used to get a complete summary of
its command-line options.
The new JMOD format goes beyond JAR files to include native code, configuration files, and other kinds of data that do not fit naturally, if at all, into JAR files. JMOD files are used to package the modules of the JDK itself; they can also be used by developers to package their own modules, if desired. The final format of JMOD files is an open issue, but for now it is based on ZIP files.
JMOD files can be used at compile time and link time, but not at run time. To support them at run time would require, in general, that we be prepared to extract and link native-code libraries on-the-fly. This is feasible on most platforms, though it can be very tricky, and we'vewe have not seen many use cases that require this capability, so for simplicity we have chosen to limit the utility of JMOD files in this release.
A new command-line tool, jmod
, can be used to create JMOD files and
list the content of existing files. Its general syntax is:
$ jmod (create|list|describe) <options> <jmod-file>
The list
and describe
subcommands accept no options; for the create
subcommand, <options>
can include the --main-class
,
--module-version
, --hash-dependenciesmodules
, and --modulepath
options
described above for the jar
tool, and also:
--class-path <path>
specifies a class path whose content will be
copied into the resulting JMOD file.
--cmds <path>
specifies one or more directories containing native
commands to be copied.
--config <path>
specifies one or more directories containing
configuration files to be copied.
--libs <path>
specifies one or more directories containing native
libraries to be copied.
--os-arch <arch>
specifies the operating-system architecture to be
recorded in the module-info.class
file.
--os-name <os>
specifies the operating-system name to be recorded
in the module-info.class
file.
--os-version <version>
specifies the operating-system version to be
recorded in the module-info.class
file.
The jmod
tool's --help
option can be used to get a complete summary
of its command-line options.
The details of the command-line linking tool, jlink
, are described in
JEP 282. At a high level its general syntax is:
$ jlink <options> --modulepath <modulepath> --output <path>
where the --modulepath
option specifies the set of observable modules
to be considered by the linker and the --output
option specifies the
path of the directory that will contain the resulting run-time image.
The other <options>
can include the --limitmods
and --addmods
options, described above, as well as additional linker-specific options.
The jlink
tool's --help
option can be used to get a complete summary
of its command-line options.
The Java command-line launcher, java,HotSpot virtual machine implements the options described above, as
applicable to run time: -upgrademodulepath
, -modulepath
, -addmods
,
-limitmods
, -XaddReads
, -XaddExports
, and -Xpatch
. These options
can be passed to the command-line launcher, java
, and also to the
JNI invocation API.
The additional options specific to this phase and supported by the launcher are:
-m <module>
specifies the main module of a modular application.
This will be the default root module for the purpose of constructing
the application's initial module graph. If the main module's
descriptor does not indicate a main class then the syntax
<module>/<class>
can be used, where <class>
names the class that
contains the application's public static void main
entry point.
-listmods
displays the names and version strings of the observable
modules, and then exits, in the same manner as java -version
.
-listmods:<module>(,<module>)*
displays the full module descriptors
of the named modules, if observable, and then exits.
Additional diagnostic options supported by the launcher include:
-Xdiag:resolver
causes the module system to describe its activities
as it constructs the initial module graph.
-Dsun.reflect.debugModuleAccessChecks
causes a thread dump to be
shown whenever an access check in the java.lang.reflect
API fails
with an IllegalAccessException
or an InaccessibleObjectException
.
This is useful for debugging when the underlying reason for a failure
is hidden because the exception is caught and not re-thrown.
-Xlog:modules=[debug|trace]
causes the VM to log debug or trace
messages as modules are defined and changed in the run-time module
graph. These options generate voluminous output during startup.
The stack traces generated for exceptions at run time have been extended
to include, when present, the names and version strings of relevant
modules. The detail strings of exceptions such as ClassCastException
,
IllegalAccessException
, and IllegalAccessError
have also been updated
to include module information. Work on similar enhancements to other
types of diagnostic information is underway.
Suppose we have an application module, com.foo.bar
, which depends upon
a library module, com.foo.baz
. If we have the source code for both
modules in the module-path directory src
:
src/com.foo.bar/module-info.java
src/com.foo.bar/com/foo/bar/Main.java
src/com.foo.baz/module-info.java
src/com.foo.baz/com/foo/baz/BazGenerator.java
then we can compile them, together:
$ javac -modulesourcepath src -d mods $(find src -name '*.java')
The output directory, mods
, is a module-path directory containing
exploded, compiled definitions of the two modules:
mods/com.foo.bar/module-info.class
mods/com.foo.bar/com/foo/bar/Main.class
mods/com.foo.baz/module-info.class
mods/com.foo.baz/com/foo/baz/BazGenerator.class
Assuming that the com.foo.bar.Main
class contains the application's
entry point, we can run these modules as-is:
$ java -mp mods -m com.foo.bar/com.foo.bar.Main
Alternatively, we can package them up into modular JAR files:
$ jar --create -f mlib/com.foo.bar-1.0.jar \
--main-class com.foo.bar.Main --module-version 1.0 \
-C mods/com.foo.bar .
$ jar --create -f mlib/com.foo.baz-1.0.jar \
--module-version 1.0 -C mods/com.foo.baz .
The mlib
directory is a module-path directory containing the packaged,
compiled definitions of the two modules:
$ ls -l mlib
-rw-r--r-- 1501 Sep 6 12:23 com.foo.bar-1.0.jar
-rw-r--r-- 1376 Sep 6 12:23 com.foo.baz-1.0.jar
We can now run the packaged modules directly:
$ java -mp mlib -m com.foo.bar
jtreg
enhancementsThe jtreg test harness supports a new declarative tag,
@modules
. It takes a series of arguments, each of which can be of the
form <module>
or <module>/<package>
. In either case the test will
only be run when the named module is present. The latter case indicates,
additionally, that the test requires access to the named package of that
module; if the package is not exported then the harness will arrange for
it to be exported to the module that contains the test.
A default set of @modules
arguments, which will be used for all tests
in a directory hierarchy that do not include such a tag, can be specified
as the value of the modules
property in a TEST.ROOT
file or in any
TEST.properties
file.
The existing @compile
tag accepts a new option, /module=<module>
.
This has the effect of using the -Xmodule
option to javac
, defined
above, to compile the specified classes as members of the named module.
The Java SE Platform API specifieshistorically specified two class loaders: The bootstrap class loader, which loads classes from the bootstrap class path, and the system class loader, which is the default delegation parent for new class loaders and, typically, the class loader used to load and start the application. The specification does not mandate the concrete types of either of these class loaders, nor their precise delegation relationship.
The JDK has, since the 1.2 release, implemented a three-level hierarchy of class loaders, where each loader delegates to the next:
The application class loader, an instance of
java.net.URLClassLoader
, loads classes from the class path and is
installed as the sytemsystem class loader unless an alternate system
loader is specified via the system property
java.system.class.loader
.
The extension class loader, also an instance of URLClassLoader
,
loads classes available via the extension mechanism and, also,
some resources and service providers built-in to the JDK. (This
loader is not mentioned explicitly in the Java SE Platform API
Specification.)
The bootstrap class loader, which is implemented solely within the
virtual machine and is represented by null
in the ClassLoader
API, loads classes from the bootstrap class path.
JDK 9 retains this three-level hierarchy, in order to preserve compatibility, while making the following changes to implement the module system:
The application class loader is no longer an instance of
URLClassLoader
but, rather, of an internal class. To locate a
class thisIt is the
default loader first searches in thefor named modules defined to it, which
may be among the system that are neither Java SE nor JDK
modules or on the application module path.
It then delegates to its parent and then, finally, it searches the
class path. Classes loaded from the class path are defined in this
loader's unnamed module.
The extension class loader is no longer an instance of
URLClassLoader
but, rather, of an internal class. It no longer
loads classes via the extension mechanism, which was removed by JEP
220. It does, however, load classes indefine selected Java SE and JDK
modules, from the upgrade module path and the system
modulesabout which more below. In its new role this loader is
known as the platform class loader, before it delegates to its parentit is available via the new
ClassLoader::getPlatformClassLoader
method, and it will be required by the
Java SE Platform API Specification.
The bootstrap class loader is implemented in both library code and
within the virtual machine, but for compatibility it is still
represented by null
in the ClassLoader
API. It defines the core
Java SE and JDK modules.
The extensionplatform class loader is retained not only for compatibility andbut,
also, to improve security. Types loaded by the bootstrap class loader
are implicitly granted all security permissions (AllPermission
), but
many of these types do not actually require all permissions. We willhave
de-privilegeprivileged modules that do not require all permissions by loadingdefining
them via the extensionto the platform class loader rather than the bootstrap class loader,
and by granting them whateverthe permissions they actually need in the default
security policy file. The Java SE and JDK modules loaded by
the extensiondefined to the
platform class loader are:
java.activation
java.annotations.common
java.compact1
java.compact2
java.compact3
java.compiler
java.corba
java.scripting
java.se
java.se.ee
java.sql
java.sql.rowset
java.transaction
java.xml.bind
java.xml.ws
jdk.accessibility
jdk.charsets
jdk.crypto.ec
jdk.crypto.pkcs11
jdk.dynalink
jdk.jsobject
jdk.localedata
jdk.naming.dns
jdk.scripting.nashorn
jdk.xml.dom
jdk.zipfs
All other Java SE and JDK modules are loaded bydefined to the bootstrap class loader except for the JDK modules that provide tools or export tool APIs, which are loaded bydefined to the application class loader. These are:
jdk.attach
jdk.compiler
jdk.hotspot.agent
jdk.internal.le
jdk.internal.opt
jdk.jartool
jdk.javadoc
jdk.jconsole
jdk.jdeps
jdk.jdi
jdk.jlink
jdk.jshell
jdk.jstatd
jdk.jvmstat
The three built-in class loaders work together to load classes as follows:
The application class loader first searches the named modules defined to all of the built-in loaders. If a suitable module is defined to one of these loaders then that loader will load the class. If a class is not found in a named module defined to one of these loaders then the application class loader delegates to its parent. If a class is not found by its parent then the application class loader searches the class path. Classes found on the class path are loaded as members of this loader's unnamed module.
The platform class loader searches the named modules defined to all of the built-in loaders. If a suitable module is defined to one of these loaders then that loader will load the class. (The platform class loader can, consequently, now delegate to the application class loader, which can be useful when a module on the upgrade module path depends upon a module on the application module path.) If a class is not found in a named module defined to one of these loaders then the application class loader delegates to its parent.
The bootstrap class loader searches the named modules defined to
itself. If a class is not found in a named module defined to the
bootstrap loader then the bootstrap class loader searches the files
and directories added to the bootstrap class path via the
-Xbootclasspath/a
option. Classes found on the bootstrap class
path are loaded as members of this loader's unnamed module.
The application and platform class loaders delegate to their respective parent loaders in order to ensure that the bootstrap class path is still searched when a class is not found in a module defined to one of the built-in loaders.
In earlier releases the -Xbootclasspath
option allows the default
bootstrap class path to be overridden, and the -Xbootclasspath/p
option
allows a sequence of files and directories to be prepended to the default
path. The computed value of this path is reported via the JDK-specific
system property sun.boot.class.path
.
With the module system in place there is no longer athe bootstrap class path
as such is empty by
default, so thesince bootstrap classes are loaded from their respective
modules. The javac
compiler only supports the -Xbootclasspath
option
in legacy mode, the java
launcher no longer supports either
option of these
options, and the system property sun.boot.class.path
will behas been removed.
The compiler's -system
option can be used to specify an alternate
source of system modules, as described above, and its -release
option
can be used to specify an alternate platform version, as described in
JEP 247 (Compile for Older Platform Versions). At run time the
-Xpatch
option, mentioned above, can be used to inject content into
modules in the initial module graph.
A related option, -Xbootclasspath/a
, allows files and directories to be
appended to the default bootstrap class path path. This option, and the
related API in the java.lang.instrument
package, is sometimes used by
instrumentation agents, so for compatibility it is still supported at run
time. Its value, if specified, is reported via the JDK-specific system
property jdk.boot.class.path.append
. This option can be passed to the
command-line launcher, java
, and also to the JNI invocation API.
Should the -addmods
option allow the intended class loader of the
added modules to be specified?
In javac
's legacy mode, are module-info.java
source files
rejected, or are they ignored?
In javac
's multi-module mode the -sourcepath
and -classpath
options are confusing. Should we disallow them?
Should jlink
support the -m
option, or some other way to specify
entry points and their relationships to command-line launchers
generated at link time?
The jlink
, jar
, and jmod
tools use GNU-style options, but
javac
and java
do not. These should these be rationalized.
The --hash-dependencies option constrains the set of modules upon which some module can depend, but it does not constrain the set of modules which can depend upon that module. The latter is necessary to prevent the abuse of qualified exports clauses in untrusted environments. The format of JMOD files must be finalized.
Should the -Xbootclasspath/a option, and the corresponding JVM TI
API, be deprecated in JDK 9 with the intent to remove them in JDK 10?
The existing @library
and @build
tags implemented by jtreg
should be extended to work well with modules.
Many existing tests will be affected by the introduction of the module
system. In JDK 9 the @modules
tag, described above, has already
been added to over 3,000 unit and regression tests, and many tests that
used the -Xbootclasspath/p
option or assumed that the system class
loader is a URLClassLoader
have been updated.
There willis, of course, be an extensive set of unit tests for the module system
itself. In the prototypeJDK 9 source forest most of the run-time tests are in the
test/jdk/jigsaw directory of the jdk
repository and the
runtime/modules directory of the hotspot
repository;
most of the compile-time tests are in the
tools/javac/modules directory of the langtools
repository.
We plan to publish earlyEarly-access builds containing the changes described here andhave been available for some time. We encourage members of the wider Java community to test their tools, libraries, and applications against these builds to help tease out any remaining compatibility issues.
The primary risks of this proposal are ones of compatibility due to changes to existing language constructs, APIs, and tools.
Changes due primarily to the introduction of the Java Platform Module System (JSR 376) include:
Applying the public
modifier to an API element no longer guarantees
that the element will be everywhere accessible. Accessibility now
depends also upon whether the package containing that element is
exported by its defining module, and whether that module is readable
by the module containing the code that is attempting to access it.
For example, code of the following form might not work correctly:
Class<?> c = Class.forName(...);
if (Modifier.isPublic(c.getModifiers()) {
// Assume that c is accessible
}
If a package is defined in both a named module and on the class path
then the package on the class path will be ignored. Hence the class
path can no longer be used to override types that are built into the
environment. The javax.transaction
package, e.g., is defined by
the java.transaction
module, so the class path will not be searched
for types in the javax.transaction
package. This restriction is
important to avoid splitting packages across class loaders and across
modules. At compile time and run time the upgrade module path can be
used to upgrade modules that are built-in into the environment. The
-Xpatch
option can be used for other ad-hoc patching.
The ClassLoader::getResource*
and Class::getResource*
methods can
no longer be used to read JDK-internal resources. Module-private
resources can be read via the Module::getResourceAsStream
method
or, alternatively, via the jrt:
URL scheme and filesystem defined
in JEP 220.
The java.lang.reflect.AccessibleObject::setAccessible
method cannot
be used to gain access to members of packages that are not exported
by their defining modules; an InaccessibleObjectException
will be
thrown. If a framework library, such as a serializer, needs access
to such members then the relevant packages must be exported to the
framework module either via exports
declarations in module
descriptors or the -XaddExports
command-line option.
JVM TI agents can no longer instrument Java code that runs early in
the startup of the run-time environment. The ClassFileLoadHook
event, in particular, is no longer sent during the primordial phase.
The VMStart
event, which signals the beginning of the start phase,
is only posted after the the VM is initialized to the point where it
can load classes in modules other than java.base
. ATwo new capability
capabilities, can_generate_early_class_hook_events
and
can_generate_early_vmstart
, can be added by agents that are capable
of handling
carefully written to handle events early in VM initialization. More
details can be found in the updated description of the
class file load hook event
and the start event.
Modules that define Java EE APIs, or APIs primarily of interest to Java EE applications, are not resolved by default for code on the class path:
The default set of root modules for the unnamed module is based upon
the java.se
module rather than the java.se.ee
module. Thus, by
default, code in the unnamed module will not have access to APIs in
the following modules:
java.activation
java.annotations.common
java.corba
java.transaction
java.xml.bind
java.xml.ws
This is an intentional, if painful, choice, driven by two goals:
To avoid unnecessary conflicts with popular libraries that define
types in some of the same packages. The widely-used
jsr305.jar
, e.g., defines annotation types in the
javax.annotation
package, which is also defined by the
java.annotations.common
module.
To make it easier for existing application servers to migrate to JDK 9. Application servers often override the content of one or more of these modules, and in the near term they are most likely to do so by continuing to place the necessary non-modular JAR files on the class path. If these modules were resolved by default then the maintainers of application servers would have to take awkward actions to exclude them in order to override them.
These modules are still part of JDK 9. Code on the class path
can be granted access to them via the -addmods java.se.ee
flag.
The run-time behavior of some Java SE APIs will changehas changed, though in ways that continue to honor their existing specifications:
The application and extensionplatform class loaders are no longer instances
of the java.net.URLClassLoader
class, as noted above. Existing
code that invokes ClassLoader::getSystemClassLoader
and blindly
casts the result to URLClassLoader
, or does the same thing with the
parent of that class loader, might not work correctly.
Some Java SE types have been de-privileged and are now loaded by the
extensionplatform class loader rather than the bootstrap class loader, as
noted above. Existing custom class loaders that delegate directly to
the bootstrap class loader might not work correctly; they should be
updated to delegate to the extensionplatform class loader, which is easily
available via the new ClassLoader::getPlatformClassLoader
method.
If the system property java.security.policy
is used to override,
rather than augment, the system's built-in security policy then the
replacement policy must grant any necessary permissions to the
de-privileged system modules loaded by the extensionplatform class loader.
There is one source-incompatible Java SE API change:
transform
method declared in the
java.lang.instrument.ClassFileTransformer
interface is now a
default method. The interface now also declares a new transform
method that makes the relevant java.lang.reflect.Module
object
available to the transformer when instrumenting classes at load time.
Existing compiled code will continue to run, but existing source code
that uses the existing five-parameter transform method as a
functional interface will no longer compile.Finally, changes due to revisions to JDK-specific APIs and tools include:
Most of the JDK's internal APIs will becomeare inaccessible by default, as
detailed in JEP 260. Existing code that depends upon these
APIs might not work correctly. A workaround is to break
encapsulation via the -XaddExports
option, defined above. (The
movement ofSelected
critical internal APIs in the sun.misc
and sun.reflect
packages to a
have been moved to the jdk.unsupported
module, proposed in as described in
JEP 260. Non-critical internal APIs in these packages, has not yetsuch as
sun.misc.BASE64{De,En}coder
, have been
implemented in the prototype; for now, the java removed.base module exports
both of these packages.)
The -Xbootclasspath
and -Xbootclasspath/p
options will behave been
removed, as noted above. At compile time, the new -release
option
can be used to specify an alternate platform version (see JEP
247). At run time, the new -Xpatch
option, described
above, can be used to inject content into system modules.
The JDK-specific system property sun.boot.class.path
will behas been
removed, since there is no longer athe bootstrap class path is empty by default.
Existing code that uses this property might not work correctly.
The JDK-specific annotation @jdk.Exported
, introduced by
JEP 179, will be removed since the information it conveys
is now recorded in the exports
declarations of module descriptors.
We have seen no evidence of this annotation being used by tools
outside of the JDK.
The META-INF/services
resource files previously found in rt.jar
and other internal artifacts are not present in the corresponding
system modules, since servicesservice providers and dependences are now
declared in module descriptors. Existing code that scans for such
files might not work correctly.
The JDK-specific system property file.encoding
can be set on the
command line via the -D
option, as before, but it will only work
when it specifies a charset defined in the base module. Existing
launch scripts that specify other charsets might not work correctly.
As with the introduction of modular images, it is impossible to determine the full impact of these changes in the abstract. We must therefore rely upon extensive internal and--- and—especially---—external testing. If some of these changes prove to be insurmountable hurdles for developers, deployers, or end users then we will investigate ways to mitigate their impact.
JEP 200 (The Modular JDK) originally defined the modules
present in the JDK in an XML document, as an interim measure. This JEP
will movemoved those definitions to proper module descriptors, i.e.,
module-info.java
and module-info.class
files, and the modules.xml
file in the root source-code repository will bewas removed.
The initial implementation of JEP 220 (Modular Run-Time Images)
in JDK 9 used a custom build-time tool to construct JRE and JDK
images. This JEP will removereplaced that tool and instead usewith the jlink
tool.
Modular JAR files can also be Multi-Release JAR files, per JEP 238.