I have the following BeanValidation code that works fine, and permits to validate that a bean annotated with:
@EnumValue(enumClass = MyTestEnum.class)
privat
My explanation on @assylias's solution:
What we want to express about the type of the class is that it's a
Class<E>, for some E, that E <: Enum<E>
but Java does not allow us to introduce a type variable E
in a method body.
Usually, we can exploit wildcard and wildcard capture to introduce a hidden type variable
class G<T extends b(T)> { ... } // b(T) is a type expression that may contain T
G<? extends A> --capture--> G<T>, for some T, that T <: A & b(T)
But this won't work in our case, since T
in Class<T>
does not have a bound that makes it work.
So we need to introduce a new type with the desired bound
class EnumClass<E extends Enum<E>> // called EnumValue in assylias's solution
EnumClass(Class<E> enumClass)
Class<E> enumClass()
EnumClass<?> --capture--> EnumClass<E>, for some E, that E <: Enum<E>
We then call EnumClass<E>.enumClass()
to yield a
Class<E>, for some E, that E <: Enum<E>
which is the goal we've been trying to achieve.
But how can we call the constructor of EnumClass
? The origin of the problem is that we don't have a proper type for enumClass
, yet the constructor of EnumClass
wants a properly typed enumClass
.
Class<not-proper> enumClass = ...;
new EnumClass<...>(enumClass); // wont work
Fortunately(?) the raw type helps here which disables generics type checking
EnumClass raw = new EnumClass(enumClass); // no generics
EnumClass<?> wild = raw;
So the minimum gymnastics we need to perform to cast the class to the desired type is
((EnumClass<?>)new EnumClass(enumClass)).enumClass()
My guess is that in ? extends Enum<?>
the two ?
could be different whereas allOf
expects a T extends Enum<T>
where both T
are the same.
For example, consider the following code:
static enum MyEnum {}
static class EnumValue<T extends Enum<T>> {
Class<T> enumClass;
EnumValue(Class<T> enumClass) {
this.enumClass = enumClass;
}
Class<T> enumClass() { return enumClass; }
}
These lines will compile:
EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass());
because we know that the two T
in enumValue.enumClass()
are the same but this won't:
EnumValue enumValue = new EnumValue(MyEnum.class);
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
because you have lost information by using a Class<? extends Enum<?>>
as an intermediate step.