CARVIEW |
Navigation Menu
-
-
Notifications
You must be signed in to change notification settings - Fork 294
TypeSignature API
See also the ClassGraph API overview.
ClassGraph parses classfile-internal type signature and type descriptor strings (like "Ljava/lang/String;"
) into type signature objects ClassTypeSignature
, MethodTypeSignature
, and TypeSignature
.
- Type signature class hierarchy
- Example usage
- Note on resolving type variables
- Type signature classes
- Additional type-related classes
The hierarchy of type signature classes reflects the structure of Java's internal type signature system.
The following methods can be used to get a TypeSignature
(getTypeSignatureOrTypeDescriptor()
is preferable to calling either getTypeSignature()
or getTypeDescriptor()
, since it will use the type signature, including generic information, if available, otherwise it will fall back to using the type descriptor, without generic information):
-
Generic class type signature:
ClassInfo#getTypeSignature()
-- returns aClassTypeSignature
for the type of the class, if the class is generic, otherwise returnsnull
. (There is no methodClassInfo#getTypeDescriptor()
-- classes don't have a type descriptor.) -
Field type signature:
FieldInfo#getTypeSignatureOrTypeDescriptor()
-- returns aTypeSignature
for the type of the field. -
Method type signature:
-
Method result type signature: call
MethodInfo#getTypeSignatureOrTypeDescriptor()
to get aMethodTypeSignature
for the type of the method, thenMethodTypeSignature#getResultType()
to get the result type of the method as aTypeSignature
. -
Method parameter type signatures: call
MethodInfo#getParameterInfo()
to get an array ofMethodParameterInfo
objects for the method parameters, then for each method parameter, callMethodParameterInfo#getTypeSignatureOrTypeDescriptor()
to get aTypeSignature
for the method parameter.
-
Method result type signature: call
For example, to check the result type of a method:
try (ScanResult scanResult = new ClassGraph().enableAllInfo()
.acceptPackages(packageName).scan()) {
ClassInfo classInfo = scanResult.getClassInfo(className);
MethodInfoList methodInfoList = classInfo.getMethodInfo(methodName);
MethodInfo methodInfo = methodInfoList.get(0); // First method named {methodName}
MethodTypeSignature methodTypeSignature = methodInfo
.getTypeSignatureOrTypeDescriptor();
TypeSignature resultTypeSignature = methodTypeSignature.getResultType();
if (resultTypeSignature instanceof ArrayTypeSignature) {
ArrayTypeSignature arrayTypeSignature =
(ArrayTypeSignature) resultTypeSignature;
System.out.println("Method " + methodInfo.getName() + " returns a "
+ arrayTypeSignature.getNumDimensions() + "-dimensional array of "
+ arrayTypeSignature.getElementTypeSignature());
} else if (resultTypeSignature instanceof BaseTypeSignature) {
BaseTypeSignature baseTypeSignature =
(BaseTypeSignature) resultTypeSignature;
System.out.println("Method " + methodInfo.getName() + " returns "
+ baseTypeSignature.getTypeStr());
} else if (resultTypeSignature instanceof ClassRefTypeSignature) {
ClassRefTypeSignature classRefTypeSignature =
(ClassRefTypeSignature) resultTypeSignature;
System.out.println("Method " + methodInfo.getName() + " returns "
+ classRefTypeSignature.getClassInfo().getName());
} else if (resultTypeSignature instanceof TypeVariableSignature) {
TypeVariableSignature typeVariableSignature =
(TypeVariableSignature) resultTypeSignature;
// Attempt to resolve type variable
TypeParameter typeParameter = typeVariableSignature.resolve();
System.out.println("Method " + methodInfo.getName()
+ " returns type variable " + typeVariableSignature.getName()
+ ", which resolves to " + typeParameter);
}
}
You probably have to cast a value of TypeSignature
returned by the ClassGraph API into the correct subclass type (e.g. ClassRefTypeSignature
) to get any useful information. For example:
public class TestReadingTypeArgs {
static class A<X> {
}
static abstract class B {
abstract A<Integer> a();
}
public static void main(String[] args) {
try (ScanResult scanResult = new ClassGraph()
.acceptPackages(TestReadingTypeArgs.class.getPackage().getName())
.enableAllInfo().scan()) {
ClassInfo bClass = scanResult.getClassInfo(B.class.getName());
MethodInfo aMethodInfo = bClass.getMethodInfo("a").get(0);
MethodTypeSignature aType = aMethodInfo.getTypeSignatureOrTypeDescriptor();
TypeSignature aResultType = aType.getResultType();
ClassRefTypeSignature aResultTypeConcrete = (ClassRefTypeSignature) aResultType;
String aTypeBaseClassName = aResultTypeConcrete.getBaseClassName();
List<TypeArgument> aTypeArgs = aResultTypeConcrete.getTypeArguments();
TypeArgument aTypeArg0 = aTypeArgs.get(0);
String aTypeArg0BaseClassName =
((ClassRefTypeSignature) aTypeArg0.getTypeSignature()).getBaseClassName();
System.out.println("Method a() returns type " + aTypeBaseClassName
+ " with argument " + aTypeArg0BaseClassName);
}
}
}
This prints:
Method a() returns type TestReadingTypeArgs$A with argument java.lang.Integer
ClassGraph currently does not automatically resolve type variables into their concrete generic types, i.e. does not substitute type arguments into type parameters. This means you may unexpectedly get TypeVariableSignature
for the type signature of a field, method, method parameter, etc., where you were expecting a concrete actual type.
ClassGraph has the method TypeVariableSignature#resolve()
for resolving type variables, by first resolving the type variable against the containing method, and then against the containing class. However, Java's type system has a lot of complex quirks, and it is complex to correctly resolve type variables in the general case. Currently this resolve()
method is somewhat simplistic. Pull requests to improve type resolution are welcome.
You may also load the class using ClassInfo#loadClass()
, then use a library like gentyref / GeAnTyRef to find the concrete and generic type signature of the class.
A type signature for a generic class, returned by ClassInfo#getTypeSignature()
.
-
.getTypeParameters
returns the type parameters of the class as aList
of [TypeParameter
] objects. -
.getSuperclassSignature()
returns aClassRefTypeSignature
for the superclass of this class. -
.getSuperinterfaceSignatures()
returns aList
ofClassRefTypeSignature
objects for the interfaces implemented by this class.
A type signature for a method, returned by ClassInfo#getTypeSignatureOrTypeDescriptor()
.
-
.getTypeParameters
returns the type parameters of the class as aList
ofTypeParameter
objects. -
.getResultType()
returns aTypeSignature
for the result type of the method. -
.getThrowsSignatures()
returns aList
ofClassRefOrTypeVariableSignature
objects for any exceptions or errors that can be thrown by the method. - To obtain method parameter type signatures, first call
MethodInfo#getParameterInfo()
to obtain an array ofMethodParameterInfo
objects, one per method parameter, and then callMethodParameterInfo#getTypeSignatureOrTypeDescriptor()
. -
.getReceiverTypeAnnotationInfo()
returns anAnnotationInfoList
of any type annotations on an explicit receiver parameter of the method, if present, otherwise returns null.
A type signature or type descriptor, representing the type of a field, the return type of a method, the type of a method parameter, etc. Subclasses are ReferenceTypeSignature
and BaseTypeSignature
.
All subclasses of TypeSignature
include the following methods:
-
.getTypeAnnotationInfo()
returns anAnnotationInfoList
of any type annotations on the type signature, if present, otherwise returns null. -
.toStringWithSimpleNames()
returns a simpler rendering of the type signature than thanTypeSignature#toString()
, by using only the simple name of any classes or annotations in the type signature.
A type signature for a base type (a primitive type or void
).
-
.getType()
returnsint.class
,long.class
,short.class
,double.class
,float.class
,char.class
,boolean.class
,byte.class
, orvoid.class
. -
.getTypeStr()
retuns"int"
,"long"
,"short"
,"double"
,"float"
,"char"
,"boolean"
,"byte"
or"void"
.
A type signature for a reference type. Subclasses are ClassRefOrTypeVariableSignature
and ArrayTypeSignature
.
A type signature for an array type.
-
.getElementTypeSignature()
returns the type of the innermost nested element type of the array (e.g. for an array of typeint[][][]
, this returns aBaseTypeSignature
representingint.class
). -
.getNumDimensions()
returns the number of dimensions of the array. -
.getNestedType()
returns aTypeSignature
for the array class with one dimension fewer, or the innermost element type if there are no nested array dimensions. -
.loadClass()
loads and returns the array class represented by the type signature (e.g.Point[][].class
). -
.loadElementClass()
loads the class for the innermost nested element type of the array, and returns aClass<?>
reference (e.g. returnsPoint.class
for a type signature corresponding toPoint[][]
). -
.getArrayClassInfo()
returns anArrayClassInfo
for the array class.
A type signature for a class reference or a type variable. Subclasses are ClassRefTypeSignature
and TypeVariableSignature
.
A type signature for a Class
reference.
-
.getBaseClassName()
returns the base name of the referenced class (without suffixes or type arguments). -
.getFullyQualifiedClassName()
returns the fully-qualified name of the referenced class (with suffixes, but without type arguments). -
.getTypeArguments()
returns the type arguments of the class reference as aList
ofTypeArgument
objects. -
.getSuffixes
returns the class suffixes (for inner classes). -
.getSuffixTypeArguments
returns the type arguments of the class reference as aList
ofList
s ofTypeArgument
objects, one list for each suffix. -
.getSuffixTypeAnnotationInfo
returns the aList
ofAnnotationInfoList
elements, one for each suffix, consisting of the type annotations of the suffix, ornull
if there are no suffix type annotations. Note that the type annotation on the base class is obtained by calling the superclass methodTypeSignature#getTypeAnnotationInfo()
. -
.getClassInfo()
returns theClassInfo
object for the referenced class, if the referenced class was encountered during scanning (causing aClassInfo
object to be created for it). May return null if the referenced class was not encountered during scanning (e.g. if the class was rejected). Even if.getClassInfo()
returns null,.loadClass()
may still be able to load the class by name. -
.loadClass()
loads the referenced class, if it has not yet been loaded, and returns aClass<?>
reference for the loaded class.-
.loadClass(boolean ignoreExceptions)
loads the referenced class, as above, but also allows you to ignore classloading exceptions (if there is an exception, it returns null instead).
-
A type signature for a type variable.
-
.getName()
returns the name of the type variable (e.g."T"
) as aString
. -
.resolve()
looks up a type variable (e.g.T
) in the defining method (or if that fails, looks up a type variable in the enclosing class), and returns theTypeParameter
with the same name (e.g.T extends com.xyz.Cls
).
A (possibly-wildcarded) generic type argument.
-
.getWildCard()
returns aWildcard
enum value, which can be one of the valuesNONE
,ANY
(i.e.?
in Java syntax),EXTENDS
andSUPER
. -
.getTypeSignature()
returns aReferenceTypeSignature
for the type bounded by the wildcard.
A generic type parameter.
-
.getName()
returns the type parameter identifier (e.g."T"
) as aString
. -
.getClassBound()
returns the type parameter class bound as aReferenceTypeSignature
. May be null if there is no class bound. -
.getInterfaceBounds()
returns the type parameter interface bounds as aList
ofReferenceTypeSignature
objects. Returns the empty list if there are no interface bounds.