Reputation: 15
I'm trying to collect Set of classes by Annotation criteria with reflections (for performance benetifs):
Reflections reflections = new Reflections(packagePrefix);
Set<Class<Foo>> foos = reflections.getTypesAnnotatedWith(BooAnnotation.class);
The problem is that I'm getting Set<Class<?>>
instead of Set<Class<Foo>>
.
I managed to check if the class is a type of Foo
by filtering the collection with .filter(Foo.class::isAssignableFrom)
.
At this point, I know that I'm working with classes that are of type Foo
. Unfortunately when casting from Class<?>
to Class<Foo>
I am getting Unchecked cast and I want to avoid that.
Here is the full block of code:
Reflections reflections = new Reflections(packagePrefix);
Set<Class<Foo>> foos = reflections.getTypesAnnotatedWith(BooAnnotation.class)
.stream()
.filter(Foo.class::isAssignableFrom)
.map(uncheckedFoo -> {
@SuppressWarnings("unchecked")
Class<Foo> foo = (Class<Foo>) uncheckedFoo;
return foo;
})
.collect(Collectors.toSet());
Any suggestions on this?
Upvotes: 1
Views: 153
Reputation: 122439
First, Class<Foo>
is for the class object representing exactly the class Foo
, and no other class. There can only be one object of type Class<Foo>
. So having a Set
of them makes no sense. It seems like you are collecting a Set
of class objects representing Foo
and its subclasses. In that case, it should be Set<Class<? extends Foo>>
.
Second, you need to get uncheckedFoo
of type Class<?>
to Class<? extends Foo>
. If you don't want to do with with an unchecked cast, you can do this in a type-safe way using Class::asSubclass()
. So you can do something along the lines of:
Set<Class<? extends Foo>> foos = reflections.getTypesAnnotatedWith(BooAnnotation.class)
.stream()
.filter(Foo.class::isAssignableFrom)
.map(uncheckedFoo -> uncheckedFoo.asSubclass(Foo.class))
.collect(Collectors.toSet());
Upvotes: 1
Reputation:
You can use a good old loop instead of a stream to make clear to the compiler that each item is assignableFrom
Foo
when casting. Otherwise it forgets that all items are of type Foo
in the next step.
Cast checking and casting have to must be in 1 step
Set<Class<Foo>> foos = new HashSet<>();
for(Class<?> i : reflections.getTypesAnnotatedWith(
BooAnnotation.class ) )
{
if(Foo.class.isAssignableFrom(i))
{
foos.add(Foo.class.cast(i)); //cast from Foo.class
}
}
Note: you can use forEach
instead of the for(:)
loop
Upvotes: 0