FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

ClassGraph Constructor API ยท classgraph/classgraph Wiki ยท GitHub

ClassGraph Constructor API

Luke Hutchison edited this page Aug 24, 2026 · 20 revisions

See also the ClassGraph API overview.

Contents

Saying what to scan

Nothing is scanned unless it is enabled, so a ClassGraph with no enable method called finds nothing at all:

try (ScanResult scanResult = new ClassGraph()
        .enableNonSystemModules()    // scan the modules of the visible module layers
        .enableClasspath()           // scan the classpath of every classloader that can be found
        .enableClassInfo().acceptPackages("com.xyz").scan()) {
    // ...
}

The methods that say where to scan come in pairs. The method with no arguments enables the sources that are found in the current runtime environment; the method that takes varargs enables exactly the sources it is given:

No arguments: scan what is in the environment Varargs: scan exactly what is named
.enableClasspath() -- every classpath element of every classloader that can be found -- the thread context classloader, the system classloader, the classloader of the class in any frame of the call stack, and the ancestors of all of those, including java.class.path .enableClassLoaders(ClassLoader...), .enableClasspathEntries(Object...)
.enableModules(), .enableSystemModules(), .enableNonSystemModules() -- the modules of the module layers that are visible to the caller .enableModuleLayers(ModuleLayer...)

So calling only the varargs method scans only what it names, and nothing from the environment -- this is how 4.x's overrideClasspath() and overrideClassLoaders() are now written. Calling both scans the environment as well as what you named, which is how 4.x's addClassLoader() and addModuleLayer() are now written. There is never a second overload of the same method name that changes the meaning of the call.

Each call adds to the end of the list of things to scan, so classpath sources are scanned in the order the calls were made. Modules are always scanned before all of them, whatever order they were enabled in, since that is the order in which the JVM resolves a class: a module is searched before the classpath, and even before a classloader delegates to its parent.

.ignoreParentClassLoaders() and .ignoreParentModuleLayers() narrow what is reached from an enabled source, and .disableJarScanning() and .disableDirScanning() narrow what kind of classpath element is read. After a scan, ScanResult#getClasspathURIs() and ScanResult#getModuleReferences() report exactly what was scanned.

๐Ÿ’ก A class in a module that was not scanned can still have its classfile read, if it is needed to complete the class graph above an accepted class -- this is what puts java.lang.Object at the top of every superclass chain, even when no module was enabled. Such a class is never added to the scan results unless .enableExternalClasses() is called. Rejecting a module with .rejectModules() prevents even this.

Configuring the ClassGraph instance

After instantiating a new ClassGraph(), you can call the following methods. Methods return this for method chaining, so you can call several of these methods in succession.

  • Logging:

    • .verbose() enables verbose logging. ClassGraph builds its own hierarchical log tree while scanning, and writes it out at the end of the scan to a java.util.logging.Logger named io.github.classgraph.ClassGraph, at level INFO. Configure that logger in your logging framework to see the output. The output can be large, and logging significantly increases the time and memory needed to scan, so this is for debugging only.
    • .verbose(boolean verbose) enables verbose logging only if the parameter is true, so that logging can be switched on by a flag without an if statement.
    • .enableRealtimeLogging() calls .verbose(), then causes all future log output to be written out as it is generated, rather than only in the log tree at the end of the scan. This can be useful for debugging issues where scanning is somehow getting stuck or taking much longer than expected.
  • Enabling class scanning:

    ๐Ÿ’ก By default, classfiles are not scanned. You must call one or more of the methods below to enable classfile scanning. (Accepting packages or classes also implicitly calls .enableClassInfo(), see below.)

    ๐Ÿ’ก If you only need to scan resources files, and not classes, then for speed, you should not call any of the following methods. You should also use .acceptPaths() rather than .acceptPackages(), so that classfile scanning is not enabled.

    ๐Ÿ’ก Important: to be able to scan classes or resources in a package, the package must export itself to the world or to ClassGraph.

    • .enableAllInfo() calls each of the eight .enable...() / .ignore...() methods listed immediately below, for convenience, enabling all relevant ClassInfo, FieldInfo, MethodInfo, MethodParameterInfo and AnnotationInfo objects to be created from the classfiles for accepted classes, for both public and non-public classes, fields, methods and annotations.

      ๐Ÿ’ก If you need to scan classfiles, but don't necessarily know yet what information about classes, methods, fields or annotations you might need, or you don't care too much about speed, always call .enableAllInfo(), to save yourself any surprises where classes, fields, methods or annotations end up missing from results. Once you decide to optimize for performance, you can instead call just the individual methods you need from the following list, to increase scanning speed.

      • .enableClassInfo() enables the scanning of classes.
        • .ignoreClassVisibility() ignores class visibility modifiers (by default only public classes are scanned).

          ๐Ÿ’ก As noted above, in modular (JPMS / Project Jigsaw) projects, the classes in a package are not visible to ClassGraph unless the package or module exports itself to the world or to ClassGraph.

      • .enableFieldInfo() enables the scanning of fields within classes.
        • .ignoreFieldVisibility() ignores field visibility modifiers (by default only public fields are scanned).
        • .enableStaticFinalFieldConstantInitializerValues() enables the scanning of constant initializer values assigned to static final fields in classes. These can be obtained from the FieldInfo object for the field, by calling FieldInfo#getConstantInitializerValue(). Note that only primitive-typed or String-typed initializer values are stored as initializer constants. Some languages (like Kotlin) may store constant initializer values for non-static / non-final fields (and these can be discovered by these methods), but technically this does not conform to the classfile spec, so you should not rely on this behavior not changing in future versions of the compiler.
      • .enableMethodInfo() enables the scanning of methods within classes.
      • .enableAnnotationInfo() enables the scanning of annotations (class annotations, method annotations, method parameter annotations, and field annotations).
  • Accepting / rejecting: If no accept criteria are provided, all packages/paths are scanned.

    ๐Ÿ’ก If no packages, classes or paths are accepted, then everything is accepted, i.e. all packages or paths are scanned. ๐Ÿ’ก As a corollary, if you accept a specific package or class, then other packages or classes will not be scanned unless they too are accepted. If you accept a specific class, other classes in the same package will not be scanned unless the package itself is also accepted (and if the package is accepted, you don't need to accept the specific class, because it resides in the package). ๐Ÿ’ก Note that package and path accepting/rejecting work the same internally, they just accept different separator characters ('.' for packages, '/' for paths), meaning that if you accept/reject a path, the corresponding package is accepted/rejected, and vice versa.

    • Glob wildcard syntax: Package and path accept/reject criteria may contain glob wildcards.

      • * matches zero or more characters within a single segment: it never crosses a . (package) or / (path) separator. So com.*.internal matches com.a.internal but not com.a.b.internal, and partial-segment globs such as com.acme.proj*.widget also work. Used alone as a segment, * must match one whole segment, so java.awt.* matches the sub-packages of java.awt, but not java.awt itself -- to scan java.awt and everything below it, use java.awt.
      • **, used as a complete segment, matches zero or more whole segments: com.**.internal matches com.internal, com.a.internal and com.a.b.internal. ** may appear at the start, in the middle, or at the end of a pattern.
      • A trailing .** or /** (e.g. com.acme.**) is accepted but redundant, since accepting or rejecting a package or path always recursively covers everything below it.
      • ** must form a complete segment: a pattern such as com.a**b.impl throws IllegalArgumentException.
      • Any number of wildcards may be used in a single pattern, e.g. com.*.internal.**.impl.
      • These rules apply to .acceptPackages(), .rejectPackages(), .acceptPaths() and .rejectPaths(). Class name globs (.acceptClasses() / .rejectClasses()), jar name globs and module name globs instead use the simpler glob syntax, where * matches zero or more of any character, including separators.
    • Packages: You can specify accept criteria using the package separator character, '.' (useful for classfile scanning):

      ๐Ÿ’ก Accept and reject packages using string literals ("com.xyz.pkg") rather than a Class reference (com.xyz.pkg.Cls.class.getPackage().getName()), since a Class reference causes the class to be loaded and initialized by the JVM just to read its package name -- and the point of ClassGraph is to find out about classes without loading them.

      • .acceptPackages(String... packageNames) specifies packages to scan. May include glob wildcards (* and ** -- see Glob wildcard syntax above).

        ๐Ÿ›‘ Omit this call to scan all packages. In other words, you never need .acceptPackages("*") or .acceptPackages("") -- by default, if no packages are accepted, all paths are scanned. ๐Ÿ’ก Automatically calls .enableClassInfo(), so call .acceptPaths() instead if you don't need to scan classes.

      • .acceptPackagesNonRecursive(String... packageNames) specifies packages to scan, without recursing to sub-packages. May not include a glob wildcard (*).

        ๐Ÿ’ก e.g. you can specify .acceptPackagesNonRecursive("com.xyz.widgets") to scan only resources in that packge, or .acceptPackagesNonRecursive("") to scan only the root package of each classpath element, but not any sub-packages. ๐Ÿ’ก Automatically calls .enableClassInfo(), so call .acceptPathsNonRecursive() instead if you don't need to scan classes.

      • .rejectPackages(String... packageNames) specifies packages that should not be scanned. May include glob wildcards (* and ** -- see Glob wildcard syntax above).

        ๐Ÿ’ก Automatically calls .enableClassInfo(), so call .rejectPaths() instead if you don't need to scan classes. ๐Ÿ’ก Rejecting packages always works recursively (i.e. rejecting a package causes the package and its sub-packages to not be scanned).

    • Paths: ...Or you can specify accept criteria using the path separator characer, '/' (useful for Resource scanning):

      ๐Ÿ’ก Note that if you just need to read a small number of specific resource files, you don't necessarily need to accept the paths that contain those files, you can also call ScanResult#getResourcesWithPathIgnoringAccept(String resourcePath) after the scan has completed, and all classpath elements will be searched for resources with the specific path, whether or not that path was accepted.

      • .acceptPaths(String... paths) specifies paths to scan, relative to the package root of the classpath element. May include glob wildcards (* and ** -- see Glob wildcard syntax above).

        ๐Ÿ›‘ Omit this call to scan all paths. In other words, you never need to call .acceptPaths("*") or .acceptPaths("") -- by default, if no paths are accepted, all paths are scanned.

      • .acceptPathsNonRecursive(String... paths) specifies paths to scan, without recursing to sub-packages. May not include a glob wildcard (*).

        ๐Ÿ’ก e.g. you can specify .acceptPathsNonRecursive("META-INF/config") to scan only resources in that directory, or .acceptPathsNonRecursive("") to scan only the root directory of each classpath element, but not any sub-directories.

      • .rejectPaths(String... paths) specifies paths that should not be scanned. May include glob wildcards (* and ** -- see Glob wildcard syntax above).

        ๐Ÿ’ก Rejecting paths always works recursively (i.e. rejecting a path causes the path and its sub-paths (sub-directories) to not be scanned).

    • Classes: You can accept/reject specific classes, not just whole packages.

      ๐Ÿ’ก If nothing is accepted, everything is. But if you accept a specific package or class, then other packages or classes will not be scanned unless they too are accepted. Therefore, if you accept a specific class, other classes in the same package will not be scanned unless the package itself is also accepted -- and if the package is accepted, you don't need to accept the specific class, because it resides within the accepted package.

      • .acceptClasses(String... classNames) accepts specific classes for scanning, even if they are not in an accepted package. May include a glob wildcard (*) in the class name, but it is not possible to match any package by glob prefix (e.g. *Suffix) without using a glob in the package name (e.g. new ClassGraph().acceptClasses("*.*Suffix")).
      • .rejectClasses(String... classNames) rejects specific classes so that they are not scanned, even if they are in an accepted package. May include a glob wildcard (*) in the class name, but it is not possible to match any package by glob prefix (e.g. *Suffix) without using a glob in the package name (e.g. new ClassGraph().rejectClasses("*.*Suffix")).
    • Jars:

      • .acceptJars(String... jarLeafNames) accepts specific jars for scanning (if not specified, all jars in the classpath are scanned to look for accepted packages). May include a glob wildcard (*). The leafname is matched ignoring case, since two filenames that differ only in case name the same file on Windows and macOS.

        ๐Ÿ’ก Only the leafname of the jar should be provided, not the full path.

      • .rejectJars(String... jarLeafNames) rejects specific jars that should not be scanned. May include a glob wildcard (*). The leafname is matched ignoring case.

        ๐Ÿ’ก Only the leafname of the jar should be provided, not the full path.

    • Modules:

      • .acceptModules(String... moduleNames) accepts specific modules for scanning. If no accept is provided, every module of an enabled kind is scanned. May include a glob wildcard (*).

        ๐Ÿ›‘ Accepting a module by name does not enable a module source: nothing is scanned from any module unless .enableModules(), .enableSystemModules(), .enableNonSystemModules() or .enableModuleLayers() is also called. Accepting a system module by name therefore needs .enableSystemModules(), which is what makes system modules (those whose name starts with java., jdk., javafx. or oracle.) eligible at all.

      • .rejectModules(String... moduleNames) rejects modules that should not be scanned. May include a glob wildcard (*). A rejected module is not even read from to complete the class graph.
    • Classpath elements containing named resources:

      • .acceptClasspathElementsContainingResourcePath(String... paths) accepts classpath elements that contain a resource with a specific path. For example, this can be used to scan only classpath elements that contain a specific configuration file.
      • .rejectClasspathElementsContainingResourcePath(String... paths) rejects classpath elements that contain a resource with a specific path.
    • System jars:

      • .enableSystemJars() enables the scanning of the JRE's own lib and ext jarfiles when they are found on the classpath. These are skipped by default for speed, since they hold the system classes of a pre-modular JRE. Automatically calls .enableClassInfo().

        ๐Ÿ’ก This is about jars, not modules: call .enableSystemModules() to scan the system modules. (In 4.x, one method enableSystemJarsAndModules() did both.)

    • Classpath element types:

      • .disableJarScanning() stops ClassGraph from scanning jars on the traditional classpath.
        • .disableNestedJarScanning() causes nested jar classpath entries (jars within jars, specified using paths of the form /path/to/outer.jar!/path/to/inner.jar) to not be scanned. Call this method if you care about scanning speed, and you have nested jars in your project, but you are sure you will never need to scan any of the nested jars.
      • .disableDirScanning() stops ClassGraph from scanning directories on the traditional classpath.

        ๐Ÿ’ก There is no disableModuleScanning(): simply do not enable a module source, and no module is scanned, or even looked for.

      • .enableURLScheme(String scheme) allows classpath elements with the given URL scheme to be fetched and scanned. Every scheme the JVM has a handler for is allowed already -- including one the application registered itself, see custom URL schemes -- except http, https, ftp and mailto, which a ClassGraph denies to begin with, so this method is only needed for those four. It also keeps a ':'-separated classpath string handed to .enableClasspathEntries(String) from being split at that scheme's own colon, which is worth doing for a custom scheme even though it needs no enabling to be fetched from. Throws IllegalArgumentException if the argument is not a URL scheme name, or is shorter than two characters, since a one-character scheme cannot be told apart from a Windows drive letter.
      • .disableURLScheme(String scheme) denies a further URL scheme. A classpath element with a denied scheme is still reported by ScanResult#getClasspathURIs() and friends, but is not fetched, so the classes and resources it holds are not found.
      • .enableRemoteJarScanning() enables classpath elements to be fetched from remote http: or https: URLs for scanning. Equivalent to calling .enableURLScheme("http").enableURLScheme("https"). Fetching over a network is off by default, as this may present a security vulnerability: a classpath is not always something the caller wrote.
  • Choosing the classpath / module path to scan: See Saying what to scan above for the rule that governs this whole group.

    ๐Ÿ’ก If you have named the classpath or the classloaders to scan, and you want to scan all packages within them, remember that simply not calling .acceptPackages(pkgs) means "scan everything".

    • Classpath:
      • .enableClasspath() scans every classpath element of every classloader that can be found in the current runtime environment. A classloader is found if it is any of the following:

        • the context classloader of the calling thread, as returned by Thread.currentThread().getContextClassLoader();
        • the classloader that loaded ClassGraph itself;
        • the system classloader, as returned by ClassLoader.getSystemClassLoader() -- this is the application classloader, unless the JVM was launched with -Djava.system.class.loader;
        • the classloader of the class in any frame of the current call stack, so that the classloader of the code that called ClassGraph is scanned even when it is none of the above; or
        • an ancestor of any of those, reached through ClassLoader#getParent().

        Every classpath element that every one of those classloaders loads classes from is scanned, whether or not the classloader exposes it publicly -- see Classpath specification mechanisms for how each supported classloader is read. Classpath elements are scanned in the order in which the classloaders that declared them would be asked to load a class, so a class that appears on the classpath more than once is reported from the copy the JVM would actually load, and each classpath element is scanned only once, however many of the classloaders declare it. The application classloader is normally one of the classloaders found, so the entries that the java.class.path system property lists are scanned too, at the position the application classloader takes in that order.

        This method takes no arguments, because it scans what is in the environment. To scan specific classloaders or specific classpath elements instead, call .enableClassLoaders(...) or .enableClasspathEntries(...) and leave this call out; calling both scans the environment as well as what you named. It does not enable the scanning of modules -- that is what the module methods below are for, and modules are always scanned first.

      • .enableClasspathEntries(String classpath) scans the given classpath, with elements separated by File.pathSeparatorChar. No classloader is asked for it, so nothing else is scanned unless it is enabled as well.

      • .enableClasspathEntries(Object... classpathElements) does the same, but each argument is one classpath entry, and is not split on File.pathSeparatorChar. An element may be of any type whose toString() is a classpath element location, e.g. String, File or Path. Throws IllegalArgumentException if any element is a ClassLoader -- pass those to .enableClassLoaders() instead.

      • .enableClasspathEntries(Iterable<?> classpathElements) does the same, for a collection. A single Path passed here is treated as one classpath entry, not as a sequence of its name elements.

      • .filterClasspathElements(Predicate<String> filter) selectively includes or excludes classpath elements based on their directory or jarfile path. The predicate returns true for elements that should be scanned.

      • .filterClasspathElementsByURL(Predicate<URL> filter) does the same, based on the classpath element's URL.

    • ClassLoaders:
      • .enableClassLoaders(ClassLoader... classLoaders) scans the classpath elements declared by the given classloaders, and by their parents, rather than by the classloaders found in the current runtime environment. Call .enableClasspath() as well to scan both. Note that you may want to use this together with .ignoreParentClassLoaders(), so that classpath entries are obtained only from the classloaders you passed in, and not from their parent classloaders.

        ๐Ÿ’ก The JDK's own application and platform classloaders do not expose the locations they load classes from, so they cannot be scanned as classloaders. Passing one in -- e.g. the value returned by ClassLoader#getSystemClassLoader() or Thread#getContextClassLoader() -- is therefore not enough on its own. The application classloader's own classpath entries are still found, since its handler falls back to the java.class.path system property; but the platform classloader loads only from the system modules, so .enableSystemModules() is what reaches its classes. (In 4.x, passing one of these classloaders silently switched on a different scanning mechanism instead. It no longer does: say what you want scanned.)

      • .ignoreParentClassLoaders() causes parent classloaders to be ignored (i.e. classpath element paths are only obtained from classloaders that are not the parent of another classloader).

      • .registerClassLoaderHandler(ClassLoaderHandler classLoaderHandler) teaches ClassGraph how to read the classpath out of a classloader that it does not already know about. ClassGraph ships with handlers for the classloaders of the common application servers, build tools and frameworks (see Classpath Specification Mechanisms), so this is only needed for a classloader that none of those handle. Registered handlers are offered each classloader before the built-in handlers are, in the order they were registered, and are never dropped, so a registered handler can also override a built-in one. Of the built-in handlers, only those that name the most specific classloader class are used, so a handler that names a subclass of URLClassLoader takes the place of the built-in URLClassLoader handler rather than running alongside it, and has to add the classloader's own URLs itself. The handlers that are kept run in turn, and a classloader or classpath entry that has already been placed keeps the position the first handler to place it gave it.

        ๐Ÿ’ก A ClassLoaderHandler has to be stateless, since one instance is shared by every scan. For work that should only happen once per scan, such as reading a container-wide set of classpath entries that every one of its classloaders would yield, call ClasspathOrder#claimOncePerScan(String), which returns true only for the first caller in each scan.

        public class MyClassLoaderHandler implements ClassLoaderHandler {
            @Override
            public boolean canHandle(Class<?> classLoaderClass, ClassGraphLog log) {
                return classIsOrExtendsOrImplements(classLoaderClass, "com.example.MyClassLoader");
            }
        
            @Override
            public void findClassLoaderOrder(ClassLoader classLoader, ClassLoaderOrder classLoaderOrder,
                    ClassGraphLog log) {
                // This classloader resolves classes parent-last, so add it before delegating to its parent
                classLoaderOrder.add(classLoader, log);
                classLoaderOrder.delegateTo(classLoader.getParent(), /* isParent = */ true, log);
            }
        
            @Override
            public void findClasspathOrder(ClassLoader classLoader, ClasspathOrder classpathOrder,
                    ClassGraphLog log) {
                classpathOrder.addClasspathEntry(((MyClassLoader) classLoader).getClasspath(), classLoader, log);
            }
        }

        The log handed to each method is null unless verbose logging is switched on, which it is not by default. Pass it straight through to the methods that take one, as above -- every one of them accepts null -- and null-check it before calling it yourself.

        A handler can also override getPackageRootPrefixes() and getLibDirPrefixes(). The first names the directories the classloader may root the package hierarchy at, which are looked for within each classpath entry and stripped if present. The second names the directories the classloader loads jarfiles from without listing them as classpath entries; the jarfiles found in one, at any depth, are added to the classpath after the entry that contains them. Both default to empty, since a classloader normally loads classes only from the classpath elements it was given -- URLClassLoader has no automatic package roots or lib dirs at all. Override one only if your classloader's own code goes looking in a directory of a fixed name:

        @Override
        public List<String> getLibDirPrefixes() {
            return List.of("my-container-lib/");
        }

        Declare a prefix only if the classloader really does look there. BOOT-INF and WEB-INF are unambiguous, because a hyphen is not legal in a Java identifier, so a directory with one of those names cannot be a package; an ordinary name like classes/ or lib/ can be, and declaring one wrongly either hides a real package or puts jarfiles that are only resources on the classpath.

        try (ScanResult scanResult = new ClassGraph()
                .registerClassLoaderHandler(new MyClassLoaderHandler())
                .enableClasspath().enableAllInfo().scan()) {
            // ...
        }
    • Module path / layers:

      ๐Ÿ’ก (See also .acceptModules(moduleName) / .rejectModules(moduleName))

      • .enableSystemModules() scans the system modules (java.*, jdk.*, javafx.*, oracle.*) of the module layers that are visible from the caller: the layers of the classes on the call stack, and the boot layer.
      • .enableNonSystemModules() scans the non-system modules of those same layers. This is what almost every application wants.
      • .enableModules() scans the modules of both kinds, i.e. it is .enableSystemModules().enableNonSystemModules().
      • .enableModuleLayers(ModuleLayer... moduleLayers) scans the non-system modules of the given module layers, and of their parent layers, rather than of the module layers that are visible from the caller. Use this if you define your own ModuleLayer but the scanning code is not running within it. Call .enableNonSystemModules() as well to scan the visible layers too, or .enableSystemModules() as well to include the system modules of the given layers.
      • .ignoreParentModuleLayers() causes parent module layers to be ignored (i.e. only module layers that are not the parent of another module layer are scanned).
  • Finding inter-class dependencies:

    • .enableInterClassDependencies() records all dependencies found between classes, by looking for class references in superclasses, interfaces, methods, fields, annotations, local variables, intermediate values within a method's code, concrete type parameters, etc. You can then call one of the following methods to determine inter-class dependencies. (You can also call .enableExternalClasses() if you want non-accepted classes in the results.)
      • ClassInfo#getClassDependencies() to find the dependencies for a single class.
      • ScanResult#getClassDependencyMap() to find the dependencies for all classes.
      • ScanResult#getReverseClassDependencyMap() to find the dependent classes for all classes (the inverse of the map in the previous method).
      • GraphVizDotFile#writeFromInterClassDependencies(scanResult, classInfoList, path), in the classgraph-viz library, to write a GraphViz .dot file showing the dependencies between classes (e.g. pass the result of ScanResult#getAllClasses() as the class list).
  • Advanced:

    • .enableExternalClasses() causes "external classes" to be returned in ClassInfoList lists (i.e. classes that were not in an accepted package, but were referred to in an accepted class' classfile, as a superclass, implemented interface, or annotation).
    • .disableRuntimeInvisibleAnnotations() causes only annotations with RetentionPolicy.RUNTIME to be scanned.
    • .enableMultiReleaseVersions() causes every version of a multi-release resource to be returned, each under its own META-INF/versions/<N>/ path prefix, rather than only the one version the running JVM would select. This is for tools that need to inspect all versions in a multi-release jar. Since a multi-release classfile can then appear more than once, this implicitly disables .enableClassInfo() and everything that depends on it, so only resources are scanned. (.enableClassInfo() likewise implicitly disables this option, so call whichever one you want last.)
    • .setMaxBufferedJarRAMSize(int maxBufferedJarRAMSize) sets the maximum number of bytes, per jar, that ClassGraph will buffer in RAM before spilling over to a temporary file on disk. This applies to a nested jar that is stored deflated within an outer jar and has to be inflated before it can be read, and to a jar downloaded from an http: or https: classpath URL. Both are rare. The default is 64MB, i.e. writing to disk is avoided wherever possible; lowering it reduces ClassGraph's memory usage if either situation arises.
    • .removeTemporaryFilesAfterScan() causes temporary files (most often, nested jars that were extracted to temporary files) to be removed before the ScanResult is returned. You can use this if you need to scan many times, but don't want to wait until you call ScanResult#close() or the JVM shuts down before temporary files are cleaned up.
  • Version:

    • ClassGraph.getVersion() is a static method returning the version number of the ClassGraph library, or "unknown" if it could not be determined.

Starting the scan

With a configured ClassGraph instance, you can call one of the following methods to start the scan, producing a ScanResult, which holds all the ClassInfo objects and Resource objects found during a scan.

๐Ÿ›‘ Make sure you call ScanResult#close() when you have finished with the ScanResult, or allocate the ScanResult in a try-with-resources block.

๐Ÿ’ก If a synchronous scan fails, it throws ClassGraphException, which extends RuntimeException, so it does not have to be declared or caught. Whatever went wrong is its cause: an InterruptedException if the calling thread was interrupted while waiting for the scan (the thread's interrupt status is restored before the exception is thrown), otherwise the exception thrown by the scan. The asynchronous methods do not wrap anything: Future#get() throws the usual ExecutionException, and the failure handler is passed the original Throwable.

  • Synchronous scanning (the standard scanning method):

    ๐Ÿ’ก This causes ClassGraph to scan in parallel with the default number of worker threads: 1.25x the number of available processors for scanning, plus up to 4 more for I/O, and never fewer than 2 in total. Blocks until scanning is complete.

    • .scan() returns a ScanResult.
    • .scan(int numParallelTasks) scans with the given number of worker threads, rather than the default number.
    • .scan(ExecutorService executorService, int numParallelTasks) scans using your own ExecutorService.
  • Asynchronous scanning:
    • .scanAsync(ExecutorService executorService, int numParallelTasks) returns a Future<ScanResult>.
    • .scanAsync(ExecutorService executorService, int numParallelTasks, Consumer<ScanResult> scanResultProcessor, Consumer<Throwable> failureHandler) calls scanResultProcessor with the ScanResult on success, and failureHandler on failure.
  • Reading the classpath / module path:

    ๐Ÿ’ก Rather than perform a full scan, ClassGraph can return all classpath elements resolved using its support for a wide range of classpath specification mechanisms. (N.B. these same methods are defined in both ClassGraph and ScanResult, except that the ClassGraph versions do not extract nested jarfiles, but the ScanResult versions do return URLs/files for nested jars, if any nested jars were extracted during classpath scanning.) ๐Ÿ’ก If reading the classpath is all you need, you can depend on the classgraph-classpath library on its own, without pulling in the scanner.

    • .getClasspath(), returns the classpath as a path String separated by File.pathSeparatorChar. Returns only the base file of each classpath entry (i.e. will not include compound URLs with package roots within a jar, or nested jars within jars, since the URL scheme separator char and the path separator char are both : on Linux and macOS).
    • .getClasspathFiles(), returns classpath entries as a List<File>. Returns only the base file of each classpath entry (i.e. will not include compound URLs with package roots within a jar, or nested jars within jars).
    • .getClasspathURIs(), returns classpath entries and modules as a List<URI>.
    • .getClasspathURLs(), returns classpath as a List<URL>. Will not include jrt: URIs for system modules or modules obtained from a jlink'd runtime image, since URL does not support the jrt: scheme.
    • .getModuleReferences(), returns the modules that would be scanned, as a List<ModuleReference>. Empty if no module source was enabled.
    • .getModulePathInfo() returns information about the module path, as specified on the commandline using --module-path, --add-modules, --patch-module, --add-exports, --add-opens, and --add-reads, as a ModulePathInfo object. If you also require the returned ModulePathInfo to include values from Add-Exports and Add-Opens entries in jarfile manifest files encountered while scanning, then call ScanResult#getModulePathInfo() instead.

Wiki pages Pages 23

Clone this wiki locally


Back | FazBrowse Home | New Git URL