Reputation: 3315
I am looking for some way to get all classes that extend a certain class and infer certain generics.
I know that using Reflections
i can get all classes that extend a class
final Reflections reflections = new Reflections("path.to.package");
Set<Class<? extends ClassBase>> classes = reflections.getSubTypesOf(ClassBase.class);
but i'm not sure how to get only those using certain generics. Here's an example of what i want to achieve
Let's assume i have ClassBase<T>
public class ClassBase<T> {}
Then i have ClassA ClassB ClassC
, all of them extending ClassBase
public class ClassA extends ClassBase<Long> {}
public class ClassB extends ClassBase<Long> {}
public class ClassC extends ClassBase<Integer> {}
How do i get only ClassA
and ClassB
? I'm even ok with getting all the classes that extend ClassBase
and then filter out those i don't need, as long as i end up with a set containing only those classes which extend ClassBase
and infer <Long>
as generic type.
Or better, i actually want a Set<Class<ClassBase<Long>>>
not just a Set<Class<ClassBase>>
which contains only those inferring Long
as generic
Upvotes: 1
Views: 419
Reputation: 9806
For people using spring and have those classes managed by the container (they are annotated with some spring annotation like @Service
, @Component
), you can get all the classes with the following approach:
@Inject Set <ClassBase <Long>> extensionsWithLongType;
Upvotes: 0
Reputation: 33905
You can look at the inferred generic type using by using the function getGenericSuperclass
and then getActualTypeArguments
Here's an example:
// Given that all classes in this set are actually subclasses of ClassBase
Set<Class<? extends ClassBase>> classes = Set.of(ClassA.class, ClassB.class, ClassC.class);
System.out.println(classes); // [class test.ClassB, class test.ClassA, class test.ClassC]
@SuppressWarnings("unchecked")
Set<Class<? extends ClassBase<Long>>> result = classes.stream()
.filter(cls -> {
// Get superclass, which is ClassBase, so assume it's also parameterized
ParameterizedType superClass = (ParameterizedType) cls.getGenericSuperclass();
Type inferred = superClass.getActualTypeArguments()[0]; // get first type argument
return inferred == Long.class; // check if it's 'Long'
})
// Can now say they all extend ClassBase<Long>
.map(cls -> (Class<? extends ClassBase<Long>>) cls)
.collect(Collectors.toSet());
System.out.println(result); // [class test.ClassA, class test.ClassB]
You get a Set<Class<? extends ClassBase<Long>>>
which holds classes that extend ClassBase<Long>
. A Set<Class<ClassBase<Long>>>
, that you ask for, should only technically hold the class ClassBase
itself, while you're actually interested in the sub classes, so you get Class<? extends ClassBase<Long>>
.
Upvotes: 2