-
-
Notifications
You must be signed in to change notification settings - Fork 285
Classpath Specification Mechanisms
Luke Hutchison edited this page Aug 5, 2021
·
58 revisions
ClassGraph handles the following classpath and module path specification mechanisms:
- The JDK 9+ module path (Project Jigsaw). ClassGraph uses this mechanism to scan all visible modules, however it is entirely implemented with reflection, so that ClassGraph can be compiled with JDK 7 for backwards compatibility.
- Can find all modules visible from the calling code's module layer: modules in the module path, system modules, and modules in jlink'd images.
- Includes support for automatic modules, non-modular jars on the module path whose module name is derived from the
Automatic-Module-Name
entry in the manifest file, or from the filename of the jar. (The module name is found by ClassGraph whether these jars are added to the module path or the traditional classpath.)
-
Multi-release jars on the traditional classpath in JDK 9+, emulating the JPMS semantics for overriding the "base section" using "versioned sections" contained in paths of the form
META-INF/versions/X
, whereX
is an integer greater than or equal to 9, and less than or equal to the running JVM version. (N.B. This requires the manifest file to contain the attributeMulti-Release: true
.) - The standard (now legacy) Java
URLClassLoader
and subclasses. - The
java.class.path
system property, supporting specification of the classpath using the-cp
JRE commandline switch. - ClassGraph includes reflection code to extract path entries from specific classloaders from a wide range of common runtime environments:
- The Spring, Spring-Boot, and Spring-Boot executable jar classloaders, including properly handling nested classpaths (jars within jars) in an optimal way, by "slicing" the jarfile to extract entries directly from nested jars (which is what Spring Boot also does for speed).
- Also works with Spring Boot Dev Tools'
RestartClassLoader
for hot reload (though you will have to run a new scan on each restart).
- Also works with Spring Boot Dev Tools'
- The JBoss WildFly classloader, including JARs and WARs nested inside EARs.
- The WebLogic classloader.
- The OSGi Eclipse
DefaultClassLoader
. - The OSGi Equinox classloader (e.g. for Eclipse PDE).
- The Apache Felix (OSGi reimplementation) classloader.
- The traditional Websphere classloader.
- The Websphere Liberty / Open Liberty classloader, in both
war
and overlay mode. - The Tomcat 8+ / Catalina
WebappClassLoaderBaseHandler
classloader. - The TomEE classloaders for servlets and JAX-RS endpoints (
TomEEWebappClassLoader
andCxfContainerClassLoader
). - The Ant classloader.
- The Plexus ClassWorlds
ClassRealm
classloader. - The Quarkus
RuntimeClassLoader
. - The Uno-Jar
JarClassLoader
, and the (older, unmaintained) One-JarJarClassLoader
. - Any unknown classloader with a predictable method such as
getClasspath()
,getClassPath()
,getURLs()
etc. (a number of method and field names are tried).
- The Spring, Spring-Boot, and Spring-Boot executable jar classloaders, including properly handling nested classpaths (jars within jars) in an optimal way, by "slicing" the jarfile to extract entries directly from nested jars (which is what Spring Boot also does for speed).
- Classes added to
lib/
orext/
directories in the JDK or JRE (this is a rare but valid way to add classes to the classpath), or any other extension directories found in thejava.ext.dirs
system property.- Note however that if you use this method to add jars to the classpath, and you want ClassGraph to scan your jars, you'll have to un-reject the scanning of system jars, or specifically accept the lib/ext jars you want to scan (see the documentation for info).
-
OS-specific site-wide
lib/
orext/
directories (i.e. directories where jarfiles may be installed such that they are accessible to all installed JREs and JDKs):-
/usr/java/packages
on Linux -
%SystemRoot%\Sun\Java\lib
,%SystemRoot%\Sun\Java\lib\ext
,%SystemRoot%\OracleJava\lib
, or%SystemRoot%\Oracle\Java\lib\ext
on Windows -
/System/Library/Java/Libraries
and/System/Library/Java/Extensions
on Mac OS X -
/usr/jdk/packages
on Solaris
-
-
Remotely-hosted jarfiles, specified using
http://
orhttps://
URLs. (Some ClassLoaders allow this.) This is disabled by default for security reasons. If.enableRemoteJarScanning()
is called before.scan()
, any remote jars are downloaded to aByteBuffer
in RAM, or if the jar is too large, the jar is spilled over to a temporary file on disk. (Note that if your classpath contains remote jars, they will be downloaded every time the classpath is scanned. Both ClassGraph and the context ClassLoader may separately download the same jarfiles.) -
Jarfiles specified using custom URL schemes. This requires the custom URL scheme for the filesystem to be enabled in ClassGraph via
.enableURLScheme("jimfs")
or similar. If a custom URI scheme is not backed by an underlyingFileSystem
implementation, thenURL.openConnection()
is used to open the URL. If the data fetched over the correction is large, it will automatically spill to a temporary file on disk. -
Classpath elements hosted on custom filesystems such as
Jimfs
https://github.com/google/jimfs). Supports scanning a classpath URL of custom scheme (e.g.jimfs://
) via the NIOFiles
andPath
APIs. This works for URLs that point to either a jarfile or to a directory (ClassGraph figures out which of these the URL points to). If you specify the URL path to a jarfile on a custom filesystem, it will be opened usingFileChannel
for speed, rather than callingURL.openConnection()
. -
Wildcarded classpath entries, e.g.
lib/*
(which includes all jars and directories inlib/
as separate classpath entries), which is allowed as of JDK 6. (Only whole-directory globs are currently supported, solib/proj*
doesn't work, but this should match the JRE's behavior.) -
Class-Path
entries in a jarfile's manifest file, whereby jarfiles may add other external jarfiles to their own classpaths, with paths resolved relative to the parent directory or parent jarfile of the manifest's jarfile. ClassGraph is able to determine the transitive closure of these references, breaking cycles if necessary. -
Bundle-ClassPath
entries in an OSGi bundle jarfile's manifest file, which allows a bundle to add nested jars to the bundle classpath, with paths resolved relative to the root of the bundle jarfile. -
Jarfiles within jarfiles (to unlimited nesting depth), e.g.
project.jar!/BOOT-INF/lib/dependency.jar
, as required by Spring-Boot, JBoss, and Felix classloaders, and probably others.- To accomplish this, ClassGraph implements a custom highly-optimized zipfile central directory parser, which is capable of handling zipfile "slices" (zipfiles nested within zipfiles, when the inner zipfile is stored rather than deflated), to arbitrary nesting depth. This allows ClassGraph to scan nested jarfiles (jarfiles within jarfiles, e.g. Spring Boot lib jars in
BOOT-INF/lib/
) without first extracting the inner jars to temporary files (the JavaZipFile
API is not capable of this). - If nested jarfiles are deflated rather than stored (which is rare), they cannot be read as a slice since they are compressed, so these jarfiles are automatically inflated to RAM (with failover to a temporary file on disk if the nested jar is over 32MB in uncompressed size).
- To accomplish this, ClassGraph implements a custom highly-optimized zipfile central directory parser, which is capable of handling zipfile "slices" (zipfiles nested within zipfiles, when the inner zipfile is stored rather than deflated), to arbitrary nesting depth. This allows ClassGraph to scan nested jarfiles (jarfiles within jarfiles, e.g. Spring Boot lib jars in
-
Zip64-format jarfiles
- ClassGraph's custom jarfile reader has full support for Zip64. This extension of the zip file format is triggered if a jarfile contains more than 65536 entries, or any entry is over 4GB in uncompressed size, or the entire jar is over 4GB in size.
- ClassGraph's jarfile reader contains workarounds for the Java
ByteBuffer
and array size limit of 2GB, by reading or mmap'ing large jarfiles in 2GB chunks, and seamlessly swapping in new chunks as needed.
- The package hierarchy being rooted at a non-root path within a jarfile, e.g.
BOOT-INF/classes/
(Spring-Boot),WEB-INF/classes/
(Tomcat), andclasses/
(Ant). (Note that the standard Java classloaders do not support this.) -
Nested lib and ext jars at the following relative paths, which are implicitly part of the classpath in some runtime environments:
lib/
lib/ext/
BOOT-INF/lib/
BOOT-INF/lib-provided/
WEB-INF/lib/
WEB-INF/lib-provided/
META-INF/lib/
-
Auto-detects nested classpath roots at the following relative paths, which are implicitly part of the classpath in some runtime environments:
classes/
test-classes/
BOOT-INF/classes/
WEB-INF/classes/
- Handles both
PARENT_FIRST
andPARENT_LAST
classloader delegation modes (used by Websphere and Spring Boot), in order to resolve classpath elements in the correct order, mirroring the delegation order of the classloaders that the classpath elements were obtained from. (Standard Java classloaders usePARENT_FIRST
delegation.) - ClassGraph supports classloading through either the classloader that a classfile was found in, or if that fails, by directly loading the class through a custom classloader that directly loads the bytecode as a resource file from the classpath or module path, and then defines the class.