Skip to content
Luke Hutchison edited this page Aug 14, 2026 · 174 revisions

See also the code examples page.

Contents

General usage pattern

  1. Create a new ClassGraph() instance, and configure it for scanning:
    • Optionally call .verbose() to enable verbose logging to stderr.
    • Enable classfile scanning, if you want to scan classes -- in the simplest case, call .enableAllInfo() to enable the scanning of classes, methods, fields, and annotations.
    • Call .acceptPackages(String... packages) to accept specific packages to scan, or .acceptPaths(String... paths) if you only want to scan resources and not classes. If you don't call either of these methods, then all packages or paths will be scanned.
  2. Start the scan, by calling .scan(), to produce a ScanResult object.

    💡 The ScanResult should be assigned in a try-with-resources block or equivalent. See ScanResult lifecycle.

  3. Query the ScanResult object: (the ScanResult object can be queried repeatedly without re-running the scan)
    • For class scan results: Call methods such as .getAllClasses(), .getAllInterfaces() etc. to get ClassInfoList lists of ClassInfo objects for classes of interest
      • Query the ClassInfo objects for class properties or class relationships of interest.

        💡 Every annotation getter comes in an All form and a Direct form. The All form includes meta-annotations -- the annotations on the element's own annotations, transitively -- and, for a class, any @Inherited annotations on its superclasses. The Direct form includes only the annotations written on the element itself.

      • ClassInfoList lists can be filtered using .filter(predicateFunction) or combined using .union(ClassInfoList... others), .intersect(ClassInfoList... others), or .exclude(ClassInfoList other), to return a new ClassInfoList representing the predicate-filtered subset, union, intersection or set difference respectively.
    • And/or for resource scan results: Call methods such as .getAllResources(), .getResourcesWithPath(path), .getResourcesWithExtension(ext) etc. to get ResourceList lists of Resource (file) objects matching a given path or filename pattern.
      • Call methods ResourceList#forEachByteArray(ByteArrayConsumer) and similar functions to open the content of each Resource object as a ByteBuffer or InputStream, or read the complete contents into a byte[] array, then pass the buffer, stream or array to a consumer method, closing the buffer or stream when the consumer exits.

You can scan either at runtime (the normal usecase), or at build time (for faster startup speed, or to support Android, since it does not use the standard Java bytecode format).

See the code examples page for specific examples of how to use the ClassGraph API.

What all the info lists have in common

Every list of scan results -- ClassInfoList, MethodInfoList, FieldInfoList, AnnotationInfoList, AnnotationParameterValueList, PackageInfoList, ModuleInfoList and ResourceList -- extends ArrayList, so it can be iterated with a for-each loop, streamed, or passed anywhere a List is expected. They also share the following.

  • A list that came from a scan is unmodifiable. add, remove, set, sort, clear and every other mutation method throw UnsupportedOperationException, whether or not the call would actually have changed anything. To sort or modify the contents, copy the list first:

    List<ClassInfo> sorted = new ArrayList<>(scanResult.getAllClasses());
    sorted.sort(Comparator.comparing(ClassInfo::getSimpleName));

    A list you construct yourself, using the public no-arg constructor of any of these classes, is modifiable.

  • Lookup by name: .get(String name) returns the entry with that name, or null if there is none, and .containsName(String name) tests for it without fetching it. .asMap() returns the whole list as a Map<String, ...> if you need to look up many names.

    • MethodInfoList is the exception, because a method name can be overloaded: there, .get(String name) returns a MethodInfoList of all methods with that name, and .getSingleMethod(String name) returns the single method with that name, or throws IllegalArgumentException if the name is overloaded.
    • ResourceList is keyed by resource path rather than by name, and has .getPaths(), .getURIs() and .getURLs() in place of the name methods below.
  • Names and strings: .getNames() returns the name of every entry as a List<String>. .getAsStrings() returns the toString() of every entry -- for a method or field list, that is the full declaration, including modifiers, generic types and annotations. .getAsStringsWithSimpleNames() does the same using simple class names rather than fully-qualified ones, which is easier to read.

  • .filter(...) returns a new list holding just the entries that your predicate accepts (on every list but AnnotationParameterValueList). ClassInfoList additionally has .union(...), .intersect(...) and .exclude(...) for combining lists.

  • .emptyList() is a static method on most of these classes, returning a shared unmodifiable empty list, which is what a query with no results gives you. No ClassGraph method ever returns null in place of an empty list, so there is no need to null-check a returned list.

  • Order: ClassInfoList, PackageInfoList and ModuleInfoList are sorted by name. The methods and fields declared by a class are listed in the order the classfile declares them, which is the order javap shows them in.

Shared supertypes

Four types exist so that code can be written against what several result types have in common, rather than against each of them separately:

  • HasName is implemented by everything with a name: ClassInfo, MethodInfo, FieldInfo, AnnotationInfo, AnnotationParameterValue, PackageInfo and ModuleInfo. It declares only .getName(), and it is what makes the name lookups above possible for every info list.
  • HasAnnotations is implemented by everything that can be annotated: ClassInfo, MethodInfo, FieldInfo, MethodParameterInfo, PackageInfo and ModuleInfo. It declares the whole annotation-query API -- .getAllAnnotationInfo(), .getDirectAnnotationInfo(), their by-name and by-Class forms, the Repeatable forms, and .hasAnnotation(...) -- so one method can take a HasAnnotations and read annotations off a class, a method, a field, a parameter, a package or a module alike.
  • ClassMemberInfo is the common superclass of MethodInfo and FieldInfo. It holds everything a method and a field have in common: the declaring class, the name, the modifiers (.getModifiers(), .isPublic(), .isStatic(), ...), the type descriptor and type signature, the annotations, and .getClassDependencies().
  • HierarchicalTypeSignature is the root of the type signature hierarchy. It declares .getTypeAnnotationInfo(), and the .toString() / .toStringWithSimpleNames() pair that renders any type signature back into Java source form.

API Index

The other libraries

Two of the libraries that ClassGraph is built out of have an API of their own, and can be used without scanning anything. There is also a library that renders a scan result as a graph. See the five libraries for how they fit together.

  • Vfs API -- read directories, jarfiles and modules through one read-only virtual filesystem, without scanning anything.
  • Classpath API -- find the classpath elements and modules a JVM loads from, without scanning them.
  • GraphViz API -- render a scan result as a GraphViz .dot file.

Clone this wiki locally