Skip to content
Luke Hutchison edited this page Nov 26, 2021 · 7 revisions

See also the ClassGraph API overview.

Contents

FieldInfo

Holds information about one field of a class. Obtained by calling ClassInfo#getFieldInfo() and similar methods.

  • Properties: (N.B. call .enableFieldInfo() before .scan() to enable field scanning, and call .ignoreFieldVisibility() before .scan() if you want to scan non-public fields.)
    • .getName() returns the name of the field as a String.
    • .getClassName() returns the name of the declaring class (i.e. the class that declares the field).
    • .getClassInfo() returns the ClassInfo object for the declaring class (i.e. the class that declares the field).
    • .getModifiers() returns the field modifier bits as an int.
    • .getModifiersStr() returns the field modifiers as a String (e.g. "public static").
    • .isPublic() returns true if the field is public.
    • .isStatic() returns true if the field is static.
    • .isFinal() returns true if the field is final.
    • .isProtected() returns true if the field is protected.
    • .isPrivate() returns true if the field is private.
    • .isTransient() returns true if the field is transient.
    • .isSynthetic() returns true if the field is synthetic.
    • .isEnum() returns true if the field is an enum constant.
    • .toStringWithSimpleNames() returns a simpler rendering of the field than than FieldInfo#toString(), by using only the simple name of any classes or annotations in the field's type.
  • Type:
    • .getTypeSignature() returns the type signature of the field (including any generic type parameters) as a TypeSignature, if available, otherwise returns null.

      🛑 Currently ClassGraph makes no attempt to resolve type variables in the types of fields. If you need concrete types for a specific type context, you will need to do the type substitution yourself.

    • .getTypeSignatureStr() returns the type signature of the field (including any generic type parameters) as a raw internal Java type signature string.
    • .getTypeDescriptor() returns the type descriptor of the field (without generic type parameters) as a TypeSignature.
    • .getTypeDescriptorStr() returns the type descriptor of the field (without any generic type parameters) as a raw internal Java type descriptor string, or null if there is no generic type signature.
    • .getTypeSignatureOrTypeDescriptor() returns the type signature of the field, if available, otherwise returns the type descriptor.
    • .getTypeSignatureOrTypeDescriptorStr() returns the raw internal type signature string of the field, if available, otherwise returns the raw internal type descriptor string of the field.
  • Constant initializer value:
    • .getConstantInitializerValue() if this is a static final field, and it is initialized with a constant literal value, and ClassGraph#enableStaticFinalFieldConstantInitializerValues() was called, this returns the constant initializer value.

      💡 Constant initializer values include string and primitive values, potentially resulting from basic math or string concatenation that can be evaluated by the compiler, but cannot be the result of object construction, other than for the case of String.

      💡 If a field is initialized to a constant primitive value, this method will return the constant wrapped in a boxed type (e.g. Integer for a primitive int-typed constant value).

  • Annotations:
    • .getAnnotationInfo() returns the annotations on this field as an AnnotationInfoList.
    • .hasAnnotation(String annotationName | Class<? extends Annotation> annotationClass) returns true if the field has the given annotation.
    • .getAnnotationInfo(String annotationName | Class<? extends Annotation> annotationClass) returns the AnnotationInfo object for the given non-@Repeatable field annotation, or null if none.
    • .getAnnotationInfoRepeatable(String annotationName | Class<? extends Annotation> annotationClass) returns the AnnotationInfo object for the given @Repeatable field annotation, as an AnnotationInfoList, or the empty list if none.
  • Classloading / reflection:
    • .loadClassAndGetField() loads the defining class, then gets the java.lang.reflection.Field object for this field.

The effect of .ignoreFieldVisibility()

If you call ClassGraph#ignoreFieldVisibility() before calling scan(), then non-public fields will be scanned, and FieldInfo objects will be added to the ScanResult for any non-public fields encountered while scanning classes.

Note that ClassGraph differs in its behavior from the Java reflection API. You will notice the following differences in behavior:

  • Java reflection:

    • Class#getFields() returns public fields but not non-public fields, for a class and all its superclasses.
    • Class#getDeclaredFields() returns public and non-public fields for a class, but not its superclasses.
  • ClassGraph:

    • ClassInfo#getFieldInfo() returns fields for a class and all its superclasses. Only public fields are returned unless ClassGraph#ignoreFieldVisibility() was called, then both public and non-public fields are returned.
    • ClassInfo#getDeclaredFieldInfo() returns fields for a class but not its superclasses. Only public fields are returned unless ClassGraph#ignoreFieldVisibility() was called, then both public and non-public fields are returned.

This difference in behavior is intended to separate the concerns of whether or not to obtain field info from superclasses from whether or not to return non-public fields, making it simpler with the ClassGraph API to find non-public fields in superclasses, and/or to filter out non-public fields from a given base class, if they are not needed. With the Java reflection API, you cannot get non-public fields from superclasses using Sub.class.getFields() -- if you do want the non-public fields, you have to iterate up through the superclass hierarchy and call .getDeclaredFields() on each superclass. Conversely, with the Java reflection API you cannot request only public fields that are declared in a base class but not its superclasses (when calling .getDeclaredFields()).

With ClassGraph, you can separately decide (1) whether or not to include fields from superclasses (by calling .getDeclaredFields() if you want only the fields of a class but not its superclasses, or .getFields() if you want the fields of a class and all of its superclasses), and (2) whether or not to include non-public fields in results (by calling .ignoreFieldVisibility() to enable non-public fields).

To illustrate, given the following classes:

public class Super {
    public int publicSuper;
    private int privateSuper;
}

public class Sub extends Super {
    public int publicSub;
    private int privateSub;
}

The following results are obtained:

Non-declared fields of Super:

Mechanism Method call Result
Java reflection Super.class.getFields() publicSuper
ClassGraph superClassInfo.getFieldInfo() publicSuper
ClassGraph after .ignoreFieldVisibility() superClassInfo.getFieldInfo() publicSuper, privateSuper

Non-declared fields of Sub:

Mechanism Method call Result
Java reflection Sub.class.getFields() publicSuper, publicSub
ClassGraph subClassInfo.getFieldInfo() publicSuper, publicSub
ClassGraph after .ignoreFieldVisibility() subClassInfo.getFieldInfo() publicSuper, publicSub, privateSuper, privateSub

Declared fields of Super:

Mechanism Method call Result
Java reflection Super.class.getDeclaredFields() publicSuper, privateSuper
ClassGraph superClassInfo.getDeclaredFieldInfo() publicSuper
ClassGraph after .ignoreFieldVisibility() superClassInfo.getDeclaredFieldInfo() publicSuper, privateSuper

Declared fields of Sub:

Mechanism Method call Result
Java reflection Sub.class.getDeclaredFields() publicSub, privateSub
ClassGraph subClassInfo.getDeclaredFieldInfo() publicSub
ClassGraph after .ignoreFieldVisibility() subClassInfo.getDeclaredFieldInfo() publicSub, privateSub

FieldInfoList

Extends ArrayList<FieldInfo> with the following convenience methods:

  • .asMap() returns the FieldInfoList as a Map<String, FieldInfo> mapping the field name to the corresponding FieldInfo object.
  • .getNames() returns a list of the names of the fields in this list as a List<String>.
  • .getAsStrings() returns a list of the result of calling .toString() on each FieldInfo object in this list, producing a List<string> of String representations of each field, including annotations, modifiers, generic type params, and field name.
    • .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 fieldName) returns true if a field of the given name is contained in this list.
  • .get(String fieldName) returns the FieldInfo object in this list with the requested name, if present, otherwise returns null.
  • .filter(FieldInfoFilter filter) returns a FieldInfoList that is a subset of the original list, obtained by applying the given filter predicate to each FieldInfo object in the list.
    • FieldInfoFilter is a FunctionalInterface with the single abstract method boolean accept(FieldInfo fieldInfo).
Clone this wiki locally