Skip to content
Luke Hutchison edited this page Dec 21, 2022 · 17 revisions

See also the ClassGraph API overview.

Contents

ClassInfo

Holds information about a class. Obtained by calling ScanResult#getAllClasses() and related methods.

  • Properties:
    • .getName() / .getSimpleName() returns the name of the class as a String. (.getName() includes the package prefix, .getSimpleName() does not.)

      🛑 IMPORTANT: Do not try to do your own classloading using the class name, e.g. using Class.forName(classInfo.getName()) -- always use ClassInfo#loadClass(), or you may end up loading the class with the wrong classloader, which can cause difficult-to-debug problems.

    • .getPackageName() returns the name of the class' package.
    • .getSourceFile() returns the value of the SourceFile attribute of a classfile.
    • .getModifiers() returns the class modifier bits as an int.
    • .getModifiersStr() returns the class modifiers as a String (e.g. "public abstract").
    • .isPublic() returns true if the class is public.
    • .isProtected() returns true if the class is protected.
    • .isPrivate() returns true if the class is private.
    • .isAbstract() returns true if the class is abstract.
    • .isSynthetic() returns true if the class is synthetic.
    • .isStatic() returns true if the class is static.
    • .isFinal() returns true if the class is final.
    • .getTypeSignature() returns the type signature of the class (including any generic type parameters) as a ClassTypeSignature, if available, otherwise returns null. See also .getTypeSignatureOrTypeDescriptor().

      🛑 Currently ClassGraph makes no attempt to resolve type variables in the types of superclasses or interfaces, or their fields or methods, by substituting type arguments for type parameters. If you need concrete types for a specific type context, you will need to do the type substitution yourself.

    • .getTypeSignatureStr() returns the raw internal Java type signature string for the class (including any generic type parameters), if available, otherwise returns null.
    • .getTypeSignatureOrTypeDescriptor() returns the ClassTypeSignature for the class, if the class is generic, otherwise it synthesizes a "class descriptor" for the class, using the class name, superclass names, and interface names, returning the class descriptor as a ClassTypeSignature (Java does not include a class descriptor in classfiles). This is useful for reading type annotations that have been added to superclasses or interfaces, since without this method there would be no way to get those type annotations for non-generic classes.
    • .getClassfileMinorVersion() and .getClassfileMajorVersion() get the classfile version for the class (or 0 if the classfile was not scanned, ie. if this was not a accepted class).
    • .toStringWithSimpleNames() returns a simpler rendering of the class than than ClassInfo#toString(), by using only the simple name of the class and any annotation classes.
  • Class type:
    • .isStandardClass() returns true if the class is not an annotation or interface.
    • .isAnnotation() returns true if the class is an annotation.
    • .isInterface() returns true if the class is an interface that is not an annotation (annotations are interfaces, and can be implemented).
    • .isInterfaceOrAnnotation() returns true if the class is an interface or an annotation (annotations are interfaces, and can be implemented).
    • .isImplementedInterface() returns true if this class is an "implemented interface" (meaning a standard interface or an annotation that has been implemented by some class).
    • .isEnum() returns true if the class is an enum.
    • .isRecord() returns true if the class is a record type (JDK 14+).
    • .isArrayClass() returns true if the ClassInfo object is an ArrayClassInfo, indicating that the class is an array class (e.g. Point[][].class).
    • .isInnerClass() returns true if the class is an inner class.
    • .isAnonymousInnerClass() returns true if the class is an anonymous inner class.
    • .isOuterClass() returns true if the class contains one or more inner classes.
  • Standard classes:
    • .getSubclasses() returns all subclasses of the class, as a ClassInfoList of ClassInfo objects representing the subclasses.
    • .getSuperclasses() returns all superclasses of the class, as a ClassInfoList of ClassInfo objects representing the superclasses.
    • .getSuperclass() returns the single direct superclasses of the class, as a ClassInfo object, or null if none.
    • .extendsSuperclass(String superclassName | Class<?> superclass) returns true if the class extends the given superclass (i.e. if the class is a subclass of the superclass).
  • Enums:
    • .getEnumConstants() returns the enum constants of an enum class as a FieldInfoList of FieldInfo objects, without loading the enum class.
    • .getEnumConstantObjects() returns the enum constants of an enum class as a List<Object>, where the objects have the same concrete type as the enum. Causes the enum class to be loaded and enum constants to be initialized.
  • Interfaces:
    • .getInterfaces() returns the list of interfaces implemented by this class or by one of its superclasses, if this is a standard class, or the superinterfaces extended by this interface, if this is an interface, as a ClassInfoList of ClassInfo objects for the interfaces. Returns the empty list if none.
    • .implementsInterface(String interfaceName | Class<?> interfaceClass) returns true if the class implements the given interface.
    • .getClassesImplementing() returns the list of the classes (and their subclasses) that implement this interface, if this is an interface, as a ClassInfoList of ClassInfo objects for the implementing classes. Returns the empty list if none.
  • Annotations: (N.B. call .enableAnnotationInfo() before .scan() to enable annotation scanning, and call .ignoreClassVisibility() if you want to scan non-public annotations.)

    💡 ClassGraph handles meta-annotation transitively. For example, in this class graph, the class A has annotation @F, B has annotations @F and @E, and C has annotation @G. The annotation classes F and E are both meta-annotated with @J, and E is also meta-annotated with @I, etc. This means that the list of all annotations on A is [J, F], and the list of all annotations on B is [D, K, H, L, J, I, E].

    • .getClassesWithAnnotation() if this class is an annotation, returns all classes that are annotated with this annotation, as a ClassInfoList of ClassInfo objects.
    • .getAnnotations() returns all annotations on this class, as a ClassInfoList of ClassInfo objects (these do not include specific annotation parameters of the annotations -- if you need annotation parameter values, call .getAnnotationInfo() instead).
    • .hasAnnotation(String annotationName | Class<? extends Annotation> annotation) returns true if this class has the given annotation.
    • .getAnnotationInfo(String annotationName | Class<? extends Annotation> annotationClass) returns the AnnotationInfo object for the given non-@Repeatable class annotation, or null if none.
    • .getAnnotationInfoRepeatable(String annotationName | Class<? extends Annotation> annotationClass) returns the AnnotationInfo object for the given@Repeatable class annotation, as an AnnotationInfoList, or the empty list if none.
    • .getAnnotationInfo() returns all annotations on this class, as an AnnotationInfoList of AnnotationInfo objects, which contain the specific annotation parameters of each annotation.
    • .getAnnotationDefaultParameterValues() if this is an annotation class, and it has default parameter values, returns the default parameter values as a List of AnnotationParameterValue objects.
  • Methods: (N.B. call .enableMethodInfo() before .scan() to enable method scanning, and call .ignoreMethodVisibility() to scan non-public methods.

    💡 The .getDeclared...() and .hasDeclared...() versions of the following methods only apply to methods defined in the base class, i.e. they exclude default methods defined in any interfaces implemented by the class, and methods inherited from the class' superclasses. See also this note on the effect of .ignoreMethodVisibility().

    • .getMethodInfo() / .getDeclaredMethodInfo() returns the methods of the class that are not constructors, as a MethodInfoList of MethodInfo objects.
    • .getMethodInfo(String methodName) / .getDeclaredMethodInfo(String methodName) returns methods of the class with the given name (constructors have the name "<init>"). May return more than one method, due to overloading.
    • .getConstructorInfo() / .getDeclaredConstructorInfo() returns constructors of the class, as a MethodInfoList of MethodInfo objects.
    • .getMethodAndConstructorInfo() / .getDeclaredMethodAndConstructorInfo() returns methods and constructors of the class, as a MethodInfoList of MethodInfo objects.
    • .hasMethod(String fieldName) / .hasDeclaredMethod(String fieldName) returns true if this class has a method with the given name.
    • .getMethodAnnotations() returns the union of classes annotating any methods declared by this class, as a ClassInfoList of ClassInfo objects. These annotations do not contain specific annotation parameters -- call .getAnnotationInfo() on a MethodInfo instance to get details on specific method annotation instances.
    • .hasMethodAnnotation(String methodAnnotationName | Class<? extends Annotation> methodAnnotationClass) / .hasDeclaredMethodAnnotation(String methodAnnotationName | Class<? extends Annotation> methodAnnotationClass) returns true if this class has a method that has the given annotation.
    • .getMethodParameterAnnotations() returns the union of classes annotating any method parameters of methods declared by this class, as a ClassInfoList of ClassInfo objects. These annotations do not contain specific annotation parameters -- call .getAnnotationInfo() on a MethodInfo instance to get details on specific method annotation instances.
    • .hasMethodParameterAnnotation(String parameterAnnotationName | Class<? extends Annotation> parameterAnnotationClass) / .hasDeclaredMethodParameterAnnotation(String parameterAnnotatinoName | Class<? extends Annotation> parameterAnnotationClass) returns true if this class has a method with a parameter that has the given annotation.
    • .getClassesWithMethodAnnotation() if this is an annotation class, returns all classes that have this class as a method annotation, as a ClassInfoList of ClassInfo objects.
    • .getClassesWithMethodParameterAnnotation() if this is an annotation class, returns all classes that have this class as a method parameter annotation, as a ClassInfoList of ClassInfo objects.
  • Fields: N.B. call .enableFieldInfo() before .scan() to enable field scanning, and call .ignoreFieldVisibility() to scan non-public fields.

    💡 The .getDeclared...() and .hasDeclared...() versions of the following methods only apply to fields defined in the base class, i.e. they exclude fields inherited from the class' superclasses. See also this note on the effect of .ignoreFieldVisibility().

    • .getFieldInfo() / .getDeclaredFieldInfo() returns fields of the class, as a FieldInfoList of FieldInfo objects.
    • .getFieldInfo(String fieldName) / .getDeclaredFieldInfo(String fieldName) returns the field of the class that has the given name, as a FieldInfo object, or null if the named field doesn't exist.
    • .hasField(String fieldName) / .hasDeclaredField(String fieldName) returns true if this class has a field with the given name.
    • .getFieldAnnotations() / .getDeclaredFieldAnnotations() returns the union of classes annotating any fields in this class, as a ClassInfoList of ClassInfo objects. These annotations do not contain specific annotation parameters -- call .getAnnotationInfo() on a FieldInfo instance to get details on specific field annotation instances.
    • .hasFieldAnnotation(String fieldAnnotationName | Class<? extends Annotation> annotationClass) / .hasDeclaredFieldAnnotation(String fieldAnnotationName | Class<? extends Annotation> annotationClass) returns true if this class has a field with the given annotation.
    • .getClassesWithFieldAnnotation() if this is an annotation class, returns all classes that have this class as a field annotation, as a ClassInfoList of ClassInfo objects.
  • Inner classes:
    • .getInnerClasses() returns the inner classes within this class, if this class is an outer class.
    • .getOuterClasses() returns the outer classes enclosing this class, if this class is an inner class.
    • .getFullyQualifiedDefiningMethodName() returns the fully-qualified method name (as a String) for the method that defined this class, if this class is an anonymous inner class, otherwise returns null.
  • Classloading:

    💡 In JDK 9+, to load non-public classes from a package (or classes extending non-public superclasses, or implementing non-public interfaces), the packages containing the class' hierarchy must be open to the world or to ClassGraph.

    • .loadClass() loads the class (if it is not already loaded), using the classloader associated with the classpath element where this classfile was found, and returns a Class<?> reference.

      🛑 Make sure that you are not trying to load classes after the ScanResult goes out of scope or ScanResult#close() is called. The ScanResult must still exist for classloading to succeed.

      • .loadClass(boolean ignoreExceptions) loads the class, returning a Class<?> reference, unless there was an exception while trying to load the class, and ignoreExceptions is true, in which case returns null.
      • .loadClass(Class<T> superclassOrInterfaceType) loads the class, casts the class reference to the requested superclass or interface type, and returns a Class<T> reference.

        🛑 Only use the Class<T> superclassOrInterfaceType parameter if the superclass or interface type is loaded by the same classloader as the loaded class, otherwise you will get a ClassCastException.

        • .loadClass(Class<T> superclassOrInterfaceType, boolean ignoreExceptions) loads the class, casts the class reference to the requested superclass or interface type, and returns a Class<T> reference. If ignoreExceptions is true, and an error occurs during either classloading or casting, returns null.
  • Location:
    • .getClasspathElementURI() returns the URI of the classpath element or module that the classfile was found within (preferred over .getClasspathElementURL(), since URL throws an exception for jrt: URI types).
    • .getClasspathElementURL() returns the URL of the classpath element or module that the classfile was found within.
    • .getClasspathElementFile() returns the File (directory or jarfile) of the classpath element that the classfile was found within, or null if the classfile was found in a module.
    • .getModuleRef() returns the ModuleRef for the module that the classfile was found within, or null if the classfile was found in a directory or jarfile.
    • .getResource() returns the Resource for the class' classfile.

ArrayClassInfo

ArrayClassInfo is a subclass of ClassInfo that is used to hold metadata about an array class, e.g. int[][].class.

An ArrayClassInfo reference is obtained from an ArrayTypeSignature by calling ArrayTypeSignature#getArrayClassInfo().

The property method ClassInfo#isArrayClass() returns true if a ClassInfo object is an ArrayClassInfo.

ArrayClassInfo is assignable to ClassInfo for convenience, but most of the ClassInfo methods return empty or default values, e.g. ArrayClassInfo#getMethodInfo() and ArrayClassInfo#getFieldInfo() both return empty lists.

However, ArrayClassInfo extends ClassInfo with the following additional methods for dealing with arrays:

  • Dimensions:
    • .getNumDimensions() gets the number of dimensions of the array as an int, e.g. returns 2 for an array type of int[][].
  • Element type:

    💡 These methods apply to the innermost element type, e.g. for an array type of int[][], the innermost element type is int (and not int[], which is the element type of the toplevel array type).

    • .getElementTypeSignature() will return the TypeSignature of the innermost element type.
    • .getElementClassInfo() gets a ClassInfo object for the innermost element type, if available. Will return null for an innermost element type whose class was not found during the scan, or when the innermost element type is a base type like int, byte, etc.
    • .loadElementClass() loads the class of the innermost element type and returns a Class<?> reference for the class, e.g. this method will return int.class if the array type is int[][].
  • Array type:
    • .getArrayTypeSignature() will return the ArrayTypeSignature object that this ArrayClassInfo was obtained from. The ArrayTypeSignature can be used to get the name of the element type without loading it, using ArrayTypeSignature#getElementTypeSignature().
    • .getTypeSignatureStr() will return the raw internal type signature of the array class, e.g. will return "[[I" for an if the array type is int[][].
    • .loadClass() creates an array class, given the element type and the number of dimensions, and returns a Class<?> reference, e.g. will return int[][].class for an array type of int[][], or pkg.X[].class for an array type of pkg.X[].

ClassInfoList

A list of ClassInfo objects. The list is deduplicated (a ClassInfoList is produced from Set<ClassInfo> internally), and the ClassInfo objects in the list are sorted in order of class name, with two exceptions: ClassInfo#getSuperclasses() returns classes sorted in ascending order of inheritance hierarchy, and ClassInfo#getOuterClasses() returns containing classes from innermost to outermost.

ClassInfoList extends ArrayList<ClassInfo> with the following convenience methods:

  • Converting to Map:

    • .asMap() returns the ClassInfoList as a Map<String, ClassInfo> mapping the class name to the corresponding ClassInfo object.
  • Working with class names:

    • .getNames() returns a list of the names of the classes in this list, as a List<string>.
    • .getAsStrings() returns a list of the result of calling .toString() on each ClassInfo object in this list, as a List<string> of String representations of each class, including annotations, modifiers, generic type params, class name, etc.
      • .getAsStringsWithSimpleNames() works like .getAsStrings(), but uses only the simple name of any referenced classes, by calling .toStringWithSimpleNames() on each list element rather than .toString().
    • .containsName(String className) returns true if a class of the given name is contained in this list.
    • .get(String className) returns the ClassInfo object in this list with the requested name, if present, otherwise returns null.
  • Filtering for direct relationships:

    • .directOnly() returns the subset of ClassInfo items that were obtained by direct relationship. For example, classInfo.getInterfaces() returns all interfaces implemented by a class, but classInfo.getInterfaces().directOnly() returns only the interfaces directly implemented by the class.
  • Filtering by class type:

    • .getStandardClasses() returns the subset of ClassInfo objects in the list that are standard classes (i.e. not interfaces or annotations).
    • .getInterfaces() returns the subset of ClassInfo objects in the list that are standard interfaces (i.e. interfaces that are not annotations).
    • .getInterfacesAndAnnotations() returns the subset of ClassInfo objects in the list that are interfaces or annotations (annotations are interfaces, and can be implemented).
    • .getImplementedInterfaces() returns the subset of ClassInfo objects in the list that are "implemented interfaces", i.e. interfaces or annotations that have been implemented by some class.
    • .getAnnotations() returns the subset of ClassInfo objects in the list that are annotations.
    • .getEnums() returns the subset of ClassInfo objects in the list that are enums.
    • .getRecords() returns the subset of ClassInfo objects in the list that are record types (JDK 14+).
    • .getAssignableTo(ClassInfo superClassOrInterface) returns the subset of ClassInfo objects in the list for which superClassOrInterfaceRef.isAssignableFrom(classRef) would return true for the corresponding class references. In other words, returns all elements of the list that extend or implement superClassOrInterface.
  • Filtering by predicate:

    • .filter(ClassInfoFilter filter) returns a ClassInfoList that is a subset of the original list, obtained by applying the given filter predicate to each ClassInfo in the list. There are a number of predicate methods in ClassInfo (with names starting with is, has, extends, and implements) that you can use directly in place of a custom ClassInfoFilter, e.g. .filter(ClassInfo::isInterface), or as part of a ClassInfoFilter, e.g. .filter(classInfo -> classInfo.hasAnnotation("com.xyz.Checked")).
      • ClassInfoFilter is a FunctionalInterface with the single abstract method boolean accept(ClassInfo classInfo).
  • Set operations:

    • .union(ClassInfoList... others) returns a ClassInfoList that is the union of this list and the others.
    • .intersect(ClassInfoList... others) returns a ClassInfoList that is the intersection of this list and the others.
    • .exclude(ClassInfoList other) returns a ClassInfoList that is the set difference of this list and the other (i.e. this \ other).
  • Classloading:

    💡 In JDK 9+, to load non-public classes from a package (or classes extending non-public superclasses, or implementing non-public interfaces), the packages containing the class' hierarchy must be open to the world or to ClassGraph.

    • .loadClasses() loads each class in the list, if not already loaded, using the classloader associated with the classpath element where this classfile was found, and returns a List of Class<?> references.

      🛑 Make sure that you are not trying to load classes after the ScanResult goes out of scope or ScanResult#close() is called. The ScanResult must still exist for classloading to succeed.

      • .loadClasses(boolean ignoreExceptions) loads each class in the class, returning aList of Class<?> references. If ignoreExceptions is true, silently skip adding entries to the list for any classes that cannot be loaded.
      • .loadClasses(Class<T> superclassOrInterfaceType) loads each class in the list, if not already loaded, casts each class reference to the requested superclass or interface type, and returns a list of Class<T> references.

        🛑 Only use the Class<T> superclassOrInterfaceType parameter if the superclass or interface type is loaded by the same classloader as each of the loaded classes, otherwise you will get a ClassCastException.

        • .loadClass(Class<T> superclassOrInterfaceType, boolean ignoreExceptions) loads each class in the list, casting the class reference to the requested superclass or interface type, and returning a List of Class<T> references. If ignoreExceptions is true, silently skip adding entries to the list for any classes that cannot be loaded or cast to the superclass or interface type.
  • Finding class dependencies:

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

    💡 See also ScanResult#getClassDependencyMap(), ScanResult#getReverseClassDependencyMap() and ClassInfoList#generateGraphVizDotFileFromInterClassDependencies().

    • ClassInfo#getClassDependencies() returns a ClassInfoList for all the classes a given class depends upon, by looking for class references in superclasses, interfaces, methods, fields, annotations, local variables, intermediate values within a method's code, concrete type parameters, etc.

Generating a GraphViz .dot file for class graph visualization

Generating a graph of basic class relationships

ClassInfoList#generateGraphVizDotFile() can be called on any ClassInfoList to generate a .dot file that can be fed into GraphViz (e.g. using dot -Tsvg < classgraph.dot > classgraph.svg) to visualize the relationships between the classes in the list. (There are several variants of this method that allow you to add more or less information to the graph.) For example, call this method on the result of ScanResult#getAllClasses() to plot the relationships between all classes, at least for basic relationships such as implemented interfaces, superclasses, and method/field types (relationships between classes that are based on code in method bodies cannot be visualized this way -- see next section).

💡 Note that you need to call .enableClassInfo(), .enableFieldInfo(), .enableMethodInfo(), .ignoreFieldVisibility(), and/or .ignoreMethodVisibility(), for relevant information to be shown in the output graph.

💡 Method parameter names will only be visible in the GraphViz output if you invoked javac with the -parameters switch (only available in JDK 8 and above). In Eclipse this setting is Project Properties > Java Compiler > Store information about method parameters (usable via reflection).

💡 See example graph output here

💡 See graph legend here

Generating a full inter-class dependency graph

Note that ClassInfoList#generateGraphVizDotFile() does not show dependencies between classes that are a result of class references in local variables or intermediate values. For that, you need full inter-class dependency analysis.

You can enable full inter-class dependency analysis by calling ClassGraph ClassGraph#enableInterClassDependencies() before #scan() (you can also call ClassGraph#enableExternalClasses() if you want to show non-accepted classes). You can then call ClassInfoList#generateGraphVizDotFileFromInterClassDependencies() to get the complete inter-class dependency graph.

There is only one arrow type in an inter-class dependency graph, indicating that a dependent class depends upon a dependency class in some way. What the exact relationship is cannot be determined without parsing the full bytecode of every method in a class, which ClassGraph does not attempt to do (ClassGraph finds these dependencies using the types of fields and methods, but also the names of classes referenced in the constant pool of the class, which is used to encode class names that are used in bytecode, e.g. for static method calls).