[Question] Load Generic Types
See original GitHub issueHey folks,
I’m using classgraph in a project and I just got stuck in a scenario with generic types.
Here’s the scenario:
@MyAnnotation
public class MyClass implements MyInterface<Type1, Type2> {
}
Steps to perform:
1 - Find all classes annotated with @MyAnnotation; 2 - Check if the class implements the interface MyInterface; 3 - Get the parameterized input and output(Type1 and Type2) classes.
I was able to accomplish this with the following code:
ScanResult scanResult = new ClassGraph()
.enableAllInfo()
.whitelistPackages("my.package")
.scan();
String annotationClassName = MyAnnotation.class.getCanonicalName();
ClassInfoList routes = scanResult.getClassesWithAnnotation(annotationClassName);
for (ClassInfo info : routes) {
ClassTypeSignature typeSignature = info.getTypeSignature();
for (ClassRefTypeSignature ref : typeSignature.getSuperinterfaceSignatures()) {
if (MyInterface.class.getName().equals(ref.getBaseClassName())) {
List<TypeArgument> args = ref.getTypeArguments();
Class<?> inputClass = Class.forName(args.get(0).toString());
Class<?> outputClass = Class.forName(args.get(1).toString());
}
}
}
This works fine for non-generic types, but if I have an implementation like:
@MyAnnotation
public class MyClass implements MyInterface<Type1, List<Type2>> {
}
This code won’t work because the object doesn’t know about its generic type at execution time, so when I try Class.forName(args.get(1).toString()) I’ll get ClassNotFoundException.
So my question is: Is there a better approach using classgraph to accomplish these 3 steps? Does classgraph offers a loadClass() method for TypeArgument?
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (6 by maintainers)
Top GitHub Comments
Turns out this is extremely complex. If you have
class X<Y, Z extends List & Y> extends S<Z>
, then the fields of typeZ
in classS
have the type bounds ofextends List implements Y
, and there’s no way to declare this type in Java source (you can only write code where the field conforms to one ofList
orY
). It gets even more complex, when it comes to determining concrete types of methods and fields, when you start bringing in default methods in interfaces (JDK 8+) and other factors.So actually I’m going to punt the resolution of generic types to the user, if they care enough to resolve type arguments using type parameters.
I’ll also make a note in the Javadoc for
ClassInfo#getMethodInfo()
andClassInfo#getFieldInfo()
that only declared methods and fields are returned – you need to iterate to supertypes to get all methods/fields.The old API will remain. If you need properly resolved types, you can use the new calls. They will be a bit slower than the old calls, but you can’t put a price on correctness. And the increase in time to compute the right type info will be nothing compared to the I/O time already needed to read the classfiles in the first place.