public interface ModuleFinder
ModuleFinder
is used to find modules during
resolution or
service binding.
A ModuleFinder
can only find one module with a given name. A
ModuleFinder
that finds modules in a sequence of directories, for
example, will locate the first occurrence of a module of a given name and
will ignore other modules of that name that appear in directories later in
the sequence.
Example usage:
Path dir1, dir2, dir3;
ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
Optional<ModuleReference> omref = finder.find("jdk.foo");
omref.ifPresent(mref -> ... );
The find
and findAll
methods
defined here can fail for several reasons. These include I/O errors, errors
detected parsing a module descriptor (module-info.class
), or in the
case of ModuleFinder
returned by ModuleFinder.of
, that
two or more modules with the same name are found in a directory.
When an error is detected then these methods throw FindException
with an appropriate cause
.
The behavior of a ModuleFinder
after a FindException
is
thrown is undefined. For example, invoking find
after an exception
is thrown may or may not scan the same modules that lead to the exception.
It is recommended that a module finder be discarded after an exception is
thrown.
A ModuleFinder
is not required to be thread safe.
- Since:
- 9
-
Method Summary
Modifier and TypeMethodDescriptionstatic ModuleFinder
compose(ModuleFinder... finders)
Returns a module finder that is composed from a sequence of zero or more module finders.Finds a reference to a module of a given name.findAll()
Returns the set of all module references that this finder can locate.static ModuleFinder
Returns a module finder that locates modules on the file system by searching a sequence of directories and/or packaged modules.static ModuleFinder
ofSystem()
Returns a module finder that locates the system modules.
-
Method Details
-
find
Finds a reference to a module of a given name.A
ModuleFinder
provides a consistent view of the modules that it locates. Iffind
is invoked several times to locate the same module (by name) then it will return the same result each time. If a module is located then it is guaranteed to be a member of the set of modules returned by thefindAll
method.- Parameters:
name
- The name of the module to find- Returns:
- A reference to a module with the given name or an empty
Optional
if not found - Throws:
FindException
- If an error occurs finding the moduleSecurityException
- If denied by the security manager
-
findAll
Set<ModuleReference> findAll()Returns the set of all module references that this finder can locate.A
ModuleFinder
provides a consistent view of the modules that it locates. IffindAll
is invoked several times then it will return the same (equals) result each time. For eachModuleReference
element in the returned set then it is guaranteed thatfind
will locate theModuleReference
if invoked to find that module.- API Note:
- This is important to have for methods such as
resolveAndBind
that need to scan the module path to find modules that provide a specific service. - Returns:
- The set of all module references that this finder locates
- Throws:
FindException
- If an error occurs finding all modulesSecurityException
- If denied by the security manager
-
ofSystem
Returns a module finder that locates the system modules. The system modules are the modules in the Java run-time image. The module finder will always findjava.base
.If there is a security manager set then its
checkPermission
method is invoked to check that the caller has been grantedRuntimePermission("accessSystemModules")
to access the system modules.- Returns:
- A
ModuleFinder
that locates the system modules - Throws:
SecurityException
- If denied by the security manager
-
of
Returns a module finder that locates modules on the file system by searching a sequence of directories and/or packaged modules. Each element in the given array is one of:A path to a directory of modules.
A path to the top-level directory of an exploded module.
A path to a packaged module.
If an element is a path to a directory of modules then each entry in the directory is a packaged module or the top-level directory of an exploded module. It is an error if a directory contains more than one module with the same name. If an element is a path to a directory, and that directory contains a file named
module-info.class
, then the directory is treated as an exploded module rather than a directory of modules.The module finder returned by this method supports modules packaged as JAR files. A JAR file with a
module-info.class
in its top-level directory, or in a versioned entry in a multi-release JAR file, is a modular JAR file and thus defines an explicit module. A JAR file that does not have amodule-info.class
in its top-level directory defines an automatic module, as follows:If the JAR file has the attribute "
Automatic-Module-Name
" in its main manifest then its value is the module name. The module name is otherwise derived from the name of the JAR file.The
version
, and the module name when the attribute "Automatic-Module-Name
" is not present, are derived from the file name of the JAR file as follows:The "
.jar
" suffix is removed.If the name matches the regular expression
"-(\\d+(\\.|$))"
then the module name will be derived from the subsequence preceding the hyphen of the first occurrence. The subsequence after the hyphen is parsed as aVersion
and ignored if it cannot be parsed as aVersion
.All non-alphanumeric characters (
[^A-Za-z0-9]
) in the module name are replaced with a dot ("."
), all repeating dots are replaced with one dot, and all leading and trailing dots are removed.As an example, a JAR file named "
foo-bar.jar
" will derive a module name "foo.bar
" and no version. A JAR file named "foo-bar-1.2.3-SNAPSHOT.jar
" will derive a module name "foo.bar
" and "1.2.3-SNAPSHOT
" as the version.
The set of packages in the module is derived from the non-directory entries in the JAR file that have names ending in "
.class
". A candidate package name is derived from the name using the characters up to, but not including, the last forward slash. All remaining forward slashes are replaced with dot ("."
). If the resulting string is a legal package name then it is assumed to be a package name. For example, if the JAR file contains the entry "p/q/Foo.class
" then the package name derived is "p.q
".The contents of entries starting with
META-INF/services/
are assumed to be service configuration files (seeServiceLoader
). If the name of a file (that followsMETA-INF/services/
) is a legal class name then it is assumed to be the fully-qualified class name of a service type. The entries in the file are assumed to be the fully-qualified class names of provider classes.If the JAR file has a
Main-Class
attribute in its main manifest, its value is a legal class name, and its package is in the set of packages derived for the module, then the value is the module main class.
If a
ModuleDescriptor
cannot be created (by means of theModuleDescriptor.Builder
API) for an automatic module thenFindException
is thrown. This can arise when the value of the "Automatic-Module-Name
" attribute is not a legal module name, a legal module name cannot be derived from the file name of the JAR file, where the JAR file contains a.class
in the top-level directory of the JAR file, where an entry in a service configuration file is not a legal class name or its package name is not in the set of packages derived for the module.In addition to JAR files, an implementation may also support modules that are packaged in other implementation specific module formats. If an element in the array specified to this method is a path to a directory of modules then entries in the directory that not recognized as modules are ignored. If an element in the array is a path to a packaged module that is not recognized then a
FindException
is thrown when the file is encountered. Paths to files that do not exist are always ignored.As with automatic modules, the contents of a packaged or exploded module may need to be scanned in order to determine the packages in the module. Whether hidden files are ignored or not is implementation specific and therefore not specified. If a
.class
file (other thanmodule-info.class
) is found in the top-level directory then it is assumed to be a class in the unnamed package and soFindException
is thrown.Finders created by this method are lazy and do not eagerly check that the given file paths are directories or packaged modules. Consequently, the
find
orfindAll
methods will only fail if invoking these methods results in searching a directory or packaged module and an error is encountered.- Parameters:
entries
- A possibly-empty array of paths to directories of modules or paths to packaged or exploded modules- Returns:
- A
ModuleFinder
that locates modules on the file system
-
compose
Returns a module finder that is composed from a sequence of zero or more module finders. Thefind
method of the resulting module finder will locate a module by invoking thefind
method of each module finder, in array index order, until either the module is found or all module finders have been searched. ThefindAll
method of the resulting module finder will return a set of modules that includes all modules located by the first module finder. The set of modules will include all modules located by the second or subsequent module finder that are not located by previous module finders in the sequence.When locating modules then any exceptions or errors thrown by the
find
orfindAll
methods of the underlying module finders will be propagated to the caller of the resulting module finder'sfind
orfindAll
methods.- Parameters:
finders
- The array of module finders- Returns:
- A
ModuleFinder
that composes a sequence of module finders
-