-
-
Notifications
You must be signed in to change notification settings - Fork 309
ScanResult API
See also the ClassGraph API overview.
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 theScanResult, or allocate theScanResultin a try-with-resources block -- seeScanResultlifecycle 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@Inheritedannotations on a superclass. The correspondinggetDirect...methods return only the classes or annotations one step away.-
Querying for a specific named class:
-
.getClassInfo(String className)returns theClassInfoobject 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
ClassInfoListofClassInfoobjects representing the classes.💡 A
ClassInfoListcan be further filtered by calling.filter(Predicate<ClassInfo>).-
.getAllClasses()returns a list of all classes, interfaces and annotations found during the scan. -
.getAllClassesAsMap()returns aMap<String, ClassInfo>from class name toClassInfofor 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 allEnumclasses. -
.getAllRecords()returns a list of allrecordtypes.
-
-
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 resultingClassInfo, returning aClassInfoList, or the empty list if no results. Each takes either the class name as aString, or aClass<?>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 returnedClassInfoListto separate the two..getDirectClassesImplementing(...)returns only the classes that name the interface directly in theirimplementsclause. -
.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@Inheritedannotations 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.)
-
-
Querying for a specific named class:
-
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 callClassGraph#enableExternalClasses()if you want non-accepted classes in the results.💡 See also
ClassInfo#getClassDependencies(), andGraphVizDotFile#writeFromInterClassDependencies()in theclassgraph-vizlibrary.-
.getClassDependencyMap()returns aMap<ClassInfo, ClassInfoList>mapping a class to the classes it depends upon. -
.getReverseClassDependencyMap()returns aMap<ClassInfo, ClassInfoList>mapping a class to the classes that depend upon it.
-
-
Packages:
-
.getPackageInfo()returns aPackageInfoListofPackageInfoobjects for all packages found while scanning. -
.getPackageInfo(String packageName)returns thePackageInfoobject for the named package, or null if the package was not found.
-
-
Modules:
-
.getModuleInfo()returns aModuleInfoListofModuleInfoobjects for all modules found while scanning. -
.getModuleInfo(String moduleName)returns theModuleInfoobject for the named module, or null if the module was not found.
-
-
Resources: Except where indicated, these methods return a
ResourceListconsisting ofResourceobjects for all the relevant file resources found in accepted paths or packages during the scan.💡 A
ResourceListcan be further filtered by calling.filter(Predicate<Resource>).-
.getAllResources()returns a list of allResourceobjects (including both classfiles and non-classfiles) found in accepted packages during the scan. -
.getAllResourcesAsMap()returns aMap<String, ResourceList>mapping from a resource path toResourcefor 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
ClassGraphandScanResult, except that theClassGraphversions do not extract nested jarfiles, but theScanResultversions do return URLs/files for nested jars, if any nested jars were extracted during classpath scanning.)-
.getClasspath(), returns the classpath as a pathStringseparated byFile.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 aList<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 aList<URI>. -
.getClasspathURLs(), returns classpath as aList<URL>. Will not includejrt:URIs for system modules or modules obtained from a jlink'd runtime image, sinceURLdoes not support thejrt:scheme. -
.getModuleReferences(), returns all visible modules as aList<ModuleReference>. -
.getModulePathInfo()returns information about the module path, as specified on the commandline using--module-path,--add-modules,--patch-module,--add-exports,--add-opensand--add-reads, together with theAdd-ExportsandAdd-Opensentries found in jarfile manifests during scanning, as aModulePathInfoobject.
-
-
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 theScanResultwas produced with. Library code that is handed aScanResultcan use these to check that it has the information it needs, rather than catching anIllegalStateException. -
Freeing resources:
-
.close()manually frees all resources used by theScanResult, including deleting any temporary files created by unzipping nested jars. If you don't manually close theScanResult, then these resources will be freed/deleted by a shutdown hook. -
.isClosed()returns true once theScanResulthas been closed.
-
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
ScanResultis closed, any further calls to its methods will throw anIllegalStateException. This also applies to many methods in other objects obtained from theScanResult, such asClassInfo,FieldInfo,MethodInfo, etc. -- so make sure you extract all the information you need from theScanResultwithin 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 (ScanResult scanResult = new ClassGraph().scan()) {
// Use scanResult here
}ClassGraph().scan().use { scanResult ->
// Use scanResult here
}new ClassGraph().scan().withCloseable { scanResult ->
// Use scanResult here
}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()
}
}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.