The uber-fast, ultra-lightweight classpath and module scanner for JVM languages.
—
The ClassGraph library provides comprehensive metadata about classes through the ClassInfo hierarchy. This includes detailed information about classes, methods, fields, annotations, and their relationships.
import io.github.classgraph.ClassInfo;
import io.github.classgraph.MethodInfo;
import io.github.classgraph.FieldInfo;
import io.github.classgraph.AnnotationInfo;
import io.github.classgraph.ClassTypeSignature;
import io.github.classgraph.PackageInfo;
import io.github.classgraph.ModuleInfo;
import java.util.List;// Get ClassInfo from ScanResult
ClassInfo classInfo = scanResult.getClassInfo("com.example.MyClass");
if (classInfo != null) {
// Basic naming and location
String name = classInfo.getName(); // "com.example.MyClass"
String simpleName = classInfo.getSimpleName(); // "MyClass"
String packageName = classInfo.getPackageName(); // "com.example"
// Container information
PackageInfo packageInfo = classInfo.getPackageInfo();
ModuleInfo moduleInfo = classInfo.getModuleInfo(); // null if not in module
// External class flag
boolean isExternal = classInfo.isExternalClass(); // true if outside scan scope
}// Classfile version information
int majorVersion = classInfo.getClassfileMajorVersion(); // e.g., 55 for Java 11
int minorVersion = classInfo.getClassfileMinorVersion(); // Usually 0
// Source file information
String sourceFile = classInfo.getSourceFile(); // e.g., "MyClass.java"// Access modifiers
int modifiers = classInfo.getModifiers();
String modifiersStr = classInfo.getModifiersStr(); // "public final"
// Visibility checks
boolean isPublic = classInfo.isPublic();
boolean isPrivate = classInfo.isPrivate();
boolean isProtected = classInfo.isProtected();
boolean isPackageVisible = classInfo.isPackageVisible();
// Modifier checks
boolean isAbstract = classInfo.isAbstract();
boolean isFinal = classInfo.isFinal();
boolean isStatic = classInfo.isStatic();
boolean isSynthetic = classInfo.isSynthetic();
// Type classification
boolean isInterface = classInfo.isInterface();
boolean isAnnotation = classInfo.isAnnotation();
boolean isEnum = classInfo.isEnum();
boolean isRecord = classInfo.isRecord(); // JDK 14+
boolean isStandardClass = classInfo.isStandardClass(); // Not interface/annotation/enum
boolean isArrayClass = classInfo.isArrayClass();
// Class nesting
boolean isInnerClass = classInfo.isInnerClass();
boolean isOuterClass = classInfo.isOuterClass();
boolean isAnonymousInnerClass = classInfo.isAnonymousInnerClass();// Inheritance checks
boolean extendsClass = classInfo.extendsSuperclass("java.util.AbstractList");
boolean extendsByClass = classInfo.extendsSuperclass(AbstractList.class);
// Interface implementation checks
boolean implementsInterface = classInfo.implementsInterface("java.util.List");
boolean implementsByClass = classInfo.implementsInterface(List.class);
// Annotation checks
boolean hasAnnotation = classInfo.hasAnnotation("javax.persistence.Entity");
boolean hasAnnotationByClass = classInfo.hasAnnotation(Entity.class);// Superclass hierarchy
ClassInfo superclass = classInfo.getSuperclass(); // Direct superclass
ClassInfoList superclasses = classInfo.getSuperclasses(); // Full hierarchy
// Subclass relationships
ClassInfoList subclasses = classInfo.getSubclasses(); // Direct and indirect
// Interface relationships
ClassInfoList interfaces = classInfo.getInterfaces(); // Implemented interfaces
ClassInfoList implementingClasses = classInfo.getClassesImplementing(); // Classes implementing this interface (if interface)
// Inner/outer class relationships
ClassInfoList innerClasses = classInfo.getInnerClasses();
ClassInfoList outerClasses = classInfo.getOuterClasses();// Check for field existence
boolean hasDeclaredField = classInfo.hasDeclaredField("userName");
boolean hasField = classInfo.hasField("userName"); // Including inherited
// Get field information
FieldInfo declaredField = classInfo.getDeclaredFieldInfo("userName");
FieldInfo field = classInfo.getFieldInfo("userName"); // Including inherited
// Get all fields
FieldInfoList declaredFields = classInfo.getDeclaredFieldInfo();
FieldInfoList allFields = classInfo.getFieldInfo(); // Including inherited
// Enum-specific field access
if (classInfo.isEnum()) {
FieldInfoList enumConstants = classInfo.getEnumConstants();
List<Object> enumConstantObjects = classInfo.getEnumConstantObjects();
}// Check for field annotations
boolean hasDeclaredFieldAnnotation = classInfo.hasDeclaredFieldAnnotation("javax.persistence.Column");
boolean hasFieldAnnotation = classInfo.hasFieldAnnotation("javax.persistence.Column"); // Including inherited
// Field annotation with class types
boolean hasColumnAnnotation = classInfo.hasFieldAnnotation(Column.class);FieldInfo fieldInfo = classInfo.getDeclaredFieldInfo("userName");
if (fieldInfo != null) {
// Basic field information
String name = fieldInfo.getName();
String className = fieldInfo.getClassName();
ClassInfo fieldClassInfo = fieldInfo.getClassInfo();
// Modifiers
int modifiers = fieldInfo.getModifiers();
String modifiersStr = fieldInfo.getModifiersStr();
boolean isTransient = fieldInfo.isTransient();
boolean isEnum = fieldInfo.isEnum();
// Type information
TypeSignature typeDescriptor = fieldInfo.getTypeDescriptor();
TypeSignature typeSignature = fieldInfo.getTypeSignature(); // Generic signature
TypeSignature typeSignatureOrDescriptor = fieldInfo.getTypeSignatureOrTypeDescriptor();
// Constant value (for static final fields)
Object constantValue = fieldInfo.getConstantInitializerValue();
// Annotation information
AnnotationInfoList annotations = fieldInfo.getAnnotationInfo();
// Load actual Field via reflection
Field reflectionField = fieldInfo.loadClassAndGetField();
}// Check for method existence
boolean hasDeclaredMethod = classInfo.hasDeclaredMethod("getUserName");
boolean hasMethod = classInfo.hasMethod("getUserName"); // Including inherited
// Get methods by name
MethodInfoList declaredMethods = classInfo.getDeclaredMethodInfo("getUserName");
MethodInfoList methods = classInfo.getMethodInfo("getUserName"); // Including inherited
// Get all methods
MethodInfoList allDeclaredMethods = classInfo.getDeclaredMethodInfo();
MethodInfoList allMethods = classInfo.getMethodInfo(); // Including inherited
// Constructor access
MethodInfoList declaredConstructors = classInfo.getDeclaredConstructorInfo();
MethodInfoList constructors = classInfo.getConstructorInfo();
// Combined method and constructor access
MethodInfoList allDeclaredMethodsAndConstructors = classInfo.getDeclaredMethodAndConstructorInfo();
MethodInfoList allMethodsAndConstructors = classInfo.getMethodAndConstructorInfo();// Check for method annotations
boolean hasDeclaredMethodAnnotation = classInfo.hasDeclaredMethodAnnotation("org.junit.Test");
boolean hasMethodAnnotation = classInfo.hasMethodAnnotation("org.junit.Test"); // Including inherited
// Parameter annotation checks
boolean hasDeclaredParamAnnotation = classInfo.hasDeclaredMethodParameterAnnotation("javax.validation.Valid");
boolean hasParamAnnotation = classInfo.hasMethodParameterAnnotation("javax.validation.Valid"); // Including inheritedMethodInfo methodInfo = classInfo.getDeclaredMethodInfo("processUser").get(0);
if (methodInfo != null) {
// Basic method information
String name = methodInfo.getName();
String className = methodInfo.getClassName();
ClassInfo methodClassInfo = methodInfo.getClassInfo();
// Modifiers
int modifiers = methodInfo.getModifiers();
String modifiersStr = methodInfo.getModifiersStr();
// Method type checks
boolean isConstructor = methodInfo.isConstructor();
boolean isSynchronized = methodInfo.isSynchronized();
boolean isBridge = methodInfo.isBridge();
boolean isVarArgs = methodInfo.isVarArgs();
boolean isNative = methodInfo.isNative();
boolean isAbstract = methodInfo.isAbstract();
boolean isStrict = methodInfo.isStrict();
boolean hasBody = methodInfo.hasBody();
boolean isDefault = methodInfo.isDefault(); // Default interface method
// Type signatures
MethodTypeSignature typeDescriptor = methodInfo.getTypeDescriptor();
MethodTypeSignature typeSignature = methodInfo.getTypeSignature();
MethodTypeSignature typeSignatureOrDescriptor = methodInfo.getTypeSignatureOrTypeDescriptor();
// Exception information
ClassInfoList thrownExceptions = methodInfo.getThrownExceptions();
String[] thrownExceptionNames = methodInfo.getThrownExceptionNames();
// Debug information
int minLineNum = methodInfo.getMinLineNum();
int maxLineNum = methodInfo.getMaxLineNum();
// Parameter information
MethodParameterInfo[] parameters = methodInfo.getParameterInfo();
boolean hasParamAnnotation = methodInfo.hasParameterAnnotation(Valid.class);
// Annotation information
AnnotationInfoList annotations = methodInfo.getAnnotationInfo();
// Load actual Method via reflection
Method reflectionMethod = methodInfo.loadClassAndGetMethod();
}MethodParameterInfo[] parameters = methodInfo.getParameterInfo();
for (MethodParameterInfo param : parameters) {
// Basic parameter info
MethodInfo containingMethod = param.getMethodInfo();
String paramName = param.getName(); // May be null if not available
// Parameter modifiers
int modifiers = param.getModifiers();
String modifiersStr = param.getModifiersStr();
// Type information
TypeSignature typeSignature = param.getTypeSignature();
TypeSignature typeDescriptor = param.getTypeDescriptor();
TypeSignature typeSignatureOrDescriptor = param.getTypeSignatureOrTypeDescriptor();
// Parameter annotations
AnnotationInfoList annotations = param.getAnnotationInfo();
AnnotationInfo validAnnotation = param.getAnnotationInfo(Valid.class);
}// Get all annotations on a class
AnnotationInfoList classAnnotations = classInfo.getAnnotationInfo();
// Get specific annotation
AnnotationInfo entityAnnotation = classInfo.getAnnotationInfo("javax.persistence.Entity");
AnnotationInfo entityByClass = classInfo.getAnnotationInfo(Entity.class);
// Repeatable annotations (Java 8+)
AnnotationInfoList repeatableAnnotations = classInfo.getAnnotationInfoRepeatable(Repeatable.class);
// Default annotation parameter values
AnnotationParameterValueList defaults = classInfo.getAnnotationDefaultParameterValues();
// Get classes annotated with this annotation (if this class is an annotation)
ClassInfoList annotatedClasses = classInfo.getClassesWithAnnotation();AnnotationInfo annotation = classInfo.getAnnotationInfo(Entity.class);
if (annotation != null) {
// Basic annotation information
String name = annotation.getName();
boolean isInherited = annotation.isInherited();
// Parameter values
AnnotationParameterValueList defaultValues = annotation.getDefaultParameterValues();
AnnotationParameterValueList actualValues = annotation.getParameterValues();
AnnotationParameterValueList allValues = annotation.getParameterValues(true); // Including defaults
// Get related class information
ClassInfo annotationClassInfo = annotation.getClassInfo();
// Load and instantiate annotation
Annotation annotationInstance = annotation.loadClassAndInstantiate();
}AnnotationParameterValueList paramValues = annotation.getParameterValues();
for (AnnotationParameterValue param : paramValues) {
String paramName = param.getName();
Object value = param.getValue();
// Value can be various types:
// - String, primitive types, Class references
// - Arrays of the above
// - Nested annotations (AnnotationInfo)
// - Enum values (AnnotationEnumValue)
if (value instanceof String) {
String stringValue = (String) value;
} else if (value instanceof AnnotationEnumValue) {
AnnotationEnumValue enumValue = (AnnotationEnumValue) value;
String enumClassName = enumValue.getClassName();
String enumConstantName = enumValue.getValueName();
Object actualEnumValue = enumValue.loadClassAndReturnEnumValue();
} else if (value instanceof AnnotationInfo) {
AnnotationInfo nestedAnnotation = (AnnotationInfo) value;
// Process nested annotation...
}
}
// Direct parameter value access
Object tableNameValue = paramValues.getValue("name");ClassInfo provides access to complete generic type information:
// Get type signature information
String typeSignatureStr = classInfo.getTypeSignatureStr();
ClassTypeSignature typeSignature = classInfo.getTypeSignature();
ClassTypeSignature typeSignatureOrDescriptor = classInfo.getTypeSignatureOrTypeDescriptor();
ClassTypeSignature typeDescriptor = classInfo.getTypeDescriptor(); // Synthetic descriptor
if (typeSignature != null) {
// Generic type parameters
List<TypeParameter> typeParameters = typeSignature.getTypeParameters();
// Superclass with generics
ClassRefTypeSignature superclassSignature = typeSignature.getSuperclassSignature();
// Implemented interfaces with generics
List<ClassRefTypeSignature> superinterfaceSignatures = typeSignature.getSuperinterfaceSignatures();
}// Get classpath element containing this class
URI classpathElementURI = classInfo.getClasspathElementURI();
URL classpathElementURL = classInfo.getClasspathElementURL();
File classpathElementFile = classInfo.getClasspathElementFile();
// Module information (if applicable)
ModuleRef moduleRef = classInfo.getModuleRef();
// Get the resource for the class file itself
Resource classResource = classInfo.getResource();// Load class with error handling
try {
Class<?> clazz = classInfo.loadClass(false); // false = don't initialize
System.out.println("Loaded: " + clazz.getName());
} catch (Exception e) {
System.err.println("Failed to load class: " + e.getMessage());
}
// Load without error handling (throws on failure)
Class<?> clazz = classInfo.loadClass();
// Load and cast with type safety
Class<? extends Service> serviceClass = classInfo.loadClass(Service.class, false);
Class<? extends Service> serviceClassThrow = classInfo.loadClass(Service.class); // Throws on errorClassInfoList serviceImpls = scanResult.getClassesImplementing("com.example.Service");
for (ClassInfo serviceClass : serviceImpls) {
// Check if it's a concrete implementation
if (!serviceClass.isAbstract() && !serviceClass.isInterface()) {
System.out.println("Service Implementation: " + serviceClass.getName());
// Check for configuration annotations
AnnotationInfo configAnnotation = serviceClass.getAnnotationInfo("com.example.Configuration");
if (configAnnotation != null) {
String configName = (String) configAnnotation.getParameterValues().getValue("name");
System.out.println(" Configuration: " + configName);
}
// Check for required dependencies via constructor parameters
MethodInfoList constructors = serviceClass.getDeclaredConstructorInfo();
for (MethodInfo constructor : constructors) {
if (constructor.isPublic()) {
MethodParameterInfo[] params = constructor.getParameterInfo();
System.out.println(" Constructor dependencies:");
for (MethodParameterInfo param : params) {
TypeSignature paramType = param.getTypeSignature();
System.out.println(" " + paramType.toString());
}
}
}
}
}ClassInfoList controllers = scanResult.getClassesWithAnnotation("org.springframework.web.bind.annotation.RestController");
for (ClassInfo controller : controllers) {
System.out.println("Controller: " + controller.getName());
// Find request mapping methods
MethodInfoList requestMethods = controller.getDeclaredMethodInfo()
.filter(method ->
method.hasAnnotation("org.springframework.web.bind.annotation.GetMapping") ||
method.hasAnnotation("org.springframework.web.bind.annotation.PostMapping") ||
method.hasAnnotation("org.springframework.web.bind.annotation.PutMapping") ||
method.hasAnnotation("org.springframework.web.bind.annotation.DeleteMapping"));
for (MethodInfo method : requestMethods) {
System.out.println(" Endpoint: " + method.getName());
// Extract HTTP method and path
AnnotationInfo getMapping = method.getAnnotationInfo("org.springframework.web.bind.annotation.GetMapping");
if (getMapping != null) {
Object pathValue = getMapping.getParameterValues().getValue("value");
if (pathValue instanceof String[]) {
String[] paths = (String[]) pathValue;
System.out.println(" GET " + Arrays.toString(paths));
}
}
// Analyze parameters for validation
MethodParameterInfo[] params = method.getParameterInfo();
for (MethodParameterInfo param : params) {
if (param.hasAnnotation("javax.validation.Valid")) {
System.out.println(" Validated parameter: " + param.getTypeSignature());
}
}
}
}The ClassInfo API provides comprehensive access to all aspects of class metadata, enabling sophisticated analysis and code generation capabilities while maintaining type safety and performance.
Install with Tessl CLI
npx tessl i tessl/maven-io-github-classgraph--classgraph