Skip to content
Luke Hutchison edited this page Aug 11, 2026 · 9 revisions

See also the ClassGraph API overview.

Contents

ScanResult

The .scan() method produces a ScanResult, which can be queried for either classes or resources (or both).

🛑 Make sure you call ScanResult#close() when you have finished with the ScanResult, or allocate the ScanResult in a try-with-resources block -- see ScanResult lifecycle below.

try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {
    // ...
}

A ScanResult holds all the ClassInfo objects and Resource objects found during a scan:

  • Classes: (N.B. call .enableClassInfo() before .scan(), and call .ignoreClassVisibility() if you want to scan non-public classes.)

    💡 Methods whose name begins with getAll... return the whole transitive closure of a relationship (all subclasses, all superinterfaces, and so on), and include annotations reached indirectly, as meta-annotations or as @Inherited annotations on a superclass. The corresponding getDirect... methods return only the classes or annotations one step away.

    • Querying for a specific named class:
      • .getClassInfo(String className) returns the ClassInfo object for the named class, or returns null if the named class was not found during the scan.
    • Querying for all classes of a given type: Except where indicated, these methods return a ClassInfoList of ClassInfo objects representing the classes.

      💡 A ClassInfoList can be further filtered by calling .filter(Predicate<ClassInfo>).

      • .getAllClasses() returns a list of all classes, interfaces and annotations found during the scan.
      • .getAllClassesAsMap() returns a Map<String, ClassInfo> from class name to ClassInfo for all classes, interfaces and annotations found during the scan.
      • .getAllStandardClasses() returns a list of all standard classes (non-annotation, non-interface classes).
      • .getAllAnnotations() returns a list of all annotations.
      • .getAllInterfaces() returns a list of all non-annotation interfaces. (Annotations are interfaces, and can be implemented.)
      • .getAllInterfacesAndAnnotations() returns a list of all interfaces and annotations (i.e. everything that can be implemented.)
      • .getAllEnums() returns a list of all Enum classes.
      • .getAllRecords() returns a list of all record types.
    • Querying for all classes related to a named class: These methods look up the named class by calling getClassInfo(className), then if the result is non-null, call the corresponding method in the resulting ClassInfo, returning a ClassInfoList, or the empty list if no results. Each takes either the class name as a String, or a Class<?> reference.
      • .getAllSubclasses(String className | Class<?> superclassRef) returns a list of classes that extend the given superclass, transitively. .getDirectSubclasses(...) returns only the classes that extend it directly.
      • .getAllSuperclasses(String className | Class<?> subclassRef) returns a list of the superclasses of the given class, transitively.
      • .getAllSuperinterfaces(String className | Class<?> classRef) returns a list of the interfaces implemented by the given class or by one of its superclasses, if this is a standard class, or the superinterfaces extended by this interface, if the class is an interface. .getDirectSuperinterfaces(...) returns only the interfaces one step up.
      • .getAllClassesImplementing(String interfaceName | Class<?> interfaceRef) returns a list of classes that implement (or have superclasses that implement) the given interface (or one of its subinterfaces). The returned list also includes the transitive subinterfaces of the interface, since an interface that extends the interface is a subtype of it -- call .getInterfaces() or .getStandardClasses() on the returned ClassInfoList to separate the two. .getDirectClassesImplementing(...) returns only the classes that name the interface directly in their implements clause.
      • .getAllSubinterfaces(String interfaceName | Class<?> interfaceRef) returns a list of the transitive subinterfaces of the given interface, i.e. the interfaces that extend it, and the interfaces that extend those. (This is the interface-hierarchy equivalent of .getAllSubclasses(), which only traverses the superclass hierarchy.) .getDirectSubinterfaces(...) returns only the interfaces that extend it directly.
      • .getClassesWithAnnotation(String annotationClassName | Class<? extends Annotation> annotationClassRef) returns a list of classes with the given class annotation or meta-annotation.
      • .getClassesWithAnyAnnotation(String... annotationClassNames | Class<? extends Annotation>... annotationClassRefs) returns a list of classes with any of the given class annotations or meta-annotations (uses an OR operator).
      • .getClassesWithAllAnnotations(String... annotationClassNames | Class<? extends Annotation>... annotationClassRefs) returns a list of classes with all of the given class annotations or meta-annotations (uses an AND operator).
      • .getAllAnnotationsOnClass(String className | Class<?> classRef) returns a list of the annotations on the named class, including meta-annotations and @Inherited annotations from its superclasses. .getDirectAnnotationsOnClass(...) returns only the annotations written on the class itself. (N.B. call .enableAnnotationInfo() before .scan(), and call .ignoreClassVisibility() if you want to scan non-public annotations.)
      • .getClassesWithMethodAnnotation(String annotationClassName | Class<? extends Annotation> annotationClassRef) returns a list of classes that have a method with an annotation of the given type. (N.B. call .enableAnnotationInfo() and .enableMethodInfo() before .scan(), and call .ignoreClassVisibility() and/or .ignoreMethodVisibility() if you want to scan non-public annotations and/or non-public methods.)
      • .getClassesWithMethodParameterAnnotation(String paramAnnotationClassName | Class<? extends Annotation> paramAnnotationClassRef) returns a list of classes that have a method with a method parameter annotation of the given type. (N.B. call .enableAnnotationInfo() and .enableMethodInfo() before .scan(), and call .ignoreClassVisibility() and/or .ignoreMethodVisibility() if you want to scan non-public annotations and/or non-public methods.)
      • .getClassesWithFieldAnnotation(String annotationClassName | Class<? extends Annotation> annotationClassRef) returns a list of classes that have a field with an annotation of the given type. (N.B. call .enableAnnotationInfo() and .enableFieldInfo() before .scan(), and call .ignoreClassVisibility() and/or .ignoreFieldVisibility() if you want to scan non-public annotations and/or non-public fields.)
  • Finding all inter-class dependencies: The following methods enable you to find dependencies 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.

    💡 Call ClassGraph#enableInterClassDependencies() before #scan() to enable the following methods; you can also call ClassGraph#enableExternalClasses() if you want non-accepted classes in the results.

    💡 See also ClassInfo#getClassDependencies(), and GraphVizDotFile#writeFromInterClassDependencies() in the classgraph-viz library.

    • .getClassDependencyMap() returns a Map<ClassInfo, ClassInfoList> mapping a class to the classes it depends upon.
    • .getReverseClassDependencyMap() returns a Map<ClassInfo, ClassInfoList> mapping a class to the classes that depend upon it.
  • Packages:

    • .getPackageInfo() returns a PackageInfoList of PackageInfo objects for all packages found while scanning.
    • .getPackageInfo(String packageName) returns the PackageInfo object for the named package, or null if the package was not found.
  • Modules:

    • .getModuleInfo() returns a ModuleInfoList of ModuleInfo objects for all modules found while scanning.
    • .getModuleInfo(String moduleName) returns the ModuleInfo object for the named module, or null if the module was not found.
  • Resources: Except where indicated, these methods return a ResourceList consisting of Resource objects for all the relevant file resources found in accepted paths or packages during the scan.

    💡 A ResourceList can be further filtered by calling .filter(Predicate<Resource>).

    • .getAllResources() returns a list of all Resource objects (including both classfiles and non-classfiles) found in accepted packages during the scan.
    • .getAllResourcesAsMap() returns a Map<String, ResourceList> mapping from a resource path to Resource for all resources (classfiles and non-classfiles) found in accepted packages during the scan. There can be more than one resource with a given path, if multiple classpath or module path elements contain resources with the same path.
    • .getResourcesWithPath(String resourcePath) returns a list of all resources with the given path (e.g. "META-INF/config/config.xml") in accepted paths or packages.
    • .getResourcesWithPathIgnoringAccept(String resourcePath) returns a list of all resources with the given path (e.g. "META-INF/config/config.xml") in any classpath element, ignoring path or package accept criteria (i.e. will return resources whether or not they are accepted, as long as they are not rejected).
    • .getResourcesWithLeafName(String leafName) returns a list of all resources with the given leafname (e.g. "config.xml") in accepted paths or packages.
    • .getResourcesWithExtension(String extension) returns a list of all resources with the given extension (e.g. "xml") in accepted paths or packages.
    • .getResourcesMatchingWildcard(String wildcardString) returns a list of all resources with paths matching the given wildcard string (which may contain globs) in accepted paths or packages. The syntax is * to match zero or more of any character other than /, ** to match zero or more of any character, ? to match one of any character, and any other Java regex syntax (such as character ranges in square brackets), with the exception of ., which is escaped before the string is passed to the regex parser.
    • .getResourcesMatchingPattern(Pattern pattern) returns a list of all resources with paths matching the given pattern in accepted paths or packages.
  • Classpath resolution: You can obtain a list of all the classpath elements that were scanned. (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.)

    • .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 all visible modules as a List<ModuleReference>.
    • .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, together with the Add-Exports and Add-Opens entries found in jarfile manifests during scanning, as a ModulePathInfo object.
  • Detecting changes to the classpath since the scan:

    • .isClasspathContentsModifiedSinceScan() re-checks the timestamps of the files and jarfiles encountered during the scan, and returns true if any of them has changed. It does not perform a full scan, so it cannot detect a directory that has newly come to match the accept criteria -- only a full scan will find those.
    • .getClasspathContentsLastModifiedMillis() returns the maximum last-modified timestamp of any accepted file, directory or jarfile encountered during the scan, re-read at the time of the call. Timestamps in the future are ignored, since they cannot be real. Note that this cannot in general tell whether the classpath itself has changed (or modules have been added or removed) if it is called twice within the same run.
  • Finding out what was enabled for the scan: .isClassInfoEnabled(), .isFieldInfoEnabled(), .isMethodInfoEnabled(), .isAnnotationInfoEnabled(), .isInterClassDependenciesEnabled(), .isExternalClassesEnabled(), .isFieldVisibilityIgnored() and .isMethodVisibilityIgnored() report the settings the ScanResult was produced with. Library code that is handed a ScanResult can use these to check that it has the information it needs, rather than catching an IllegalStateException.

  • Freeing resources:

    • .close() manually frees all resources used by the ScanResult, including deleting any temporary files created by unzipping nested jars. If you don't manually close the ScanResult, then these resources will be freed/deleted by a shutdown hook.
    • .isClosed() returns true once the ScanResult has been closed.

ScanResult lifecycle

Important: The ScanResult should be assigned in a try-with-resources block or equivalent to free resources allocated during the scan as soon as they are no longer needed (including closing or unmapping open or mapped files, deleting any temporary files that had to be created to read nested jars, closing module references, and freeing memory).

🛑 After the ScanResult is closed, any further calls to its methods will throw an IllegalStateException. This also applies to many methods in other objects obtained from the ScanResult, such as ClassInfo, FieldInfo, MethodInfo, etc. -- so make sure you extract all the information you need from the ScanResult within the try-with-resources block, and store it in your own data structures, rather than keeping references to objects provided by ClassGraph outside the try-with-resources block.

try-with-resources in Java:

try (ScanResult scanResult = new ClassGraph().scan()) {
    // Use scanResult here
}

.use { ... } in Kotlin:

ClassGraph().scan().use { scanResult ->
    // Use scanResult here
}

.withCloseable { ... } in Groovy:

new ClassGraph().scan().withCloseable { scanResult ->
    // Use scanResult here
}

finally block in Scala:

Scala does not yet have try-with-resources. You will need to close the ScanResult in a finally block. It is best to put val scanResult = ... inside a block too, so that the reference is not still visible after the finally block is executed.

{
  val scanResult = new ClassGraph().scan()
  try {
      // Use scanResult here
  } finally {
      scanResult.close()
  }
}

Closing all ScanResult instances

If you want to close all open (unclosed) ScanResult instances at once, you can call the static method ScanResult.closeAll(). To be safe (to ensure you don't leak any resources), you might want to call this on container unload/destroy in a containerized runtime.

Note that if you call ScanResult.closeAll(), you need to ensure that the lifecycle of the classloader matches the lifecycle of your application, or that two concurrent applications don't share the same classloader, since this is a static method -- otherwise one application might close another application's ScanResult instances while they are still in use.

Clone this wiki locally