Enum.valueOf(Class<T> enumType, String name) question
Solution 1
I think it won't work exactly like this unless you have access to a type variable (through either a type or method signature). The problem is the method signature of Enum.valueOf
:
public static <T extends Enum<T>> T valueOf(
Class<T> enumType,
String name
);
There's no way to get a T without a type variable. But you can do it like this if you're willing to suppress some compiler warnings:
public enum King{
ELVIS
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(final String[] args){
final Class<? extends Enum> enumType = King.class;
final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS");
System.out.println(theOneAndOnly.name());
}
Output:
ELVIS
Solution 2
The problem is with Class<? extends Enum<?>>
. We want E extends Enum<E>
, but we can't get that because we have two distinct wildcards.
So we need to introduce a generic parameter, possible introduced by calling a method:
enum MyEnum {
ME;
}
public class EnName {
public static void main(String[] args) {
Enum<?> value = of(MyEnum.class, "ME");
System.err.println(value);
}
private static <E extends Enum<E>> E of(Class<E> clazz, String name) {
E value = Enum.valueOf(clazz, name);
return value;
}
}
But reflection is mucky and very rarely what you want. Don't do it.
Solution 3
There's actually an alternate approach: you can use Class.getEnumConstants
and roll your own implementation of Enum.valueOf
that doesn't have the same type problems. The downside is you get back a generic Enum<?>
- but if you knew what type you had coming in, you would be able to use Enum.valueOf
anyway.
private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) {
return Arrays.stream(enumType.getEnumConstants())
.filter(e -> e.name().equals(value))
.findFirst()
.orElse(null);
}
(Note that my version returns null
if there's no such constant rather than throwing an IllegalArgumentException
, but that's a trivial thing to change.
Tom
Updated on September 08, 2021Comments
-
Tom over 2 years
I am trying to get around a compile error ("Bound mismatch: ...") relating to dynamic enum lookup.
Basically I want to achieve something like this:
String enumName = whatever.getEnumName(); Class<? extends Enum<?>> enumClass = whatever.getEnumClass(); Enum<?> enumValue = Enum.valueOf(enumClass, enumName);
Whatever I do, I always end up with that compile error. Honestly, generics and enums are quite mindboggling to me...
What am I doing wrong here?
-
Brett over 13 yearsThe question is about enums, generics and reflection. If you ignore generics, what's the point? Particularly going for "rare types" like
Class<? extends Enum>
. -
Sean Patrick Floyd over 13 yearsThe point is that a) it can't work otherwise without a helper method or type and b) we know for sure that any
Class<? extends Enum>
will also satisfyClass<E extends Enum<E>>
(because that's the way enum classes work) even though there is no way to check that without a type variable.@SuppressWarnings
is an annotation you should only use if you know what you are doing, and I do know. -
Tom over 13 yearsThanks for this explanation, it helped a lot to further understand whats going on. Since in my particular use case I don't have anything to provide as the generic parameter, I will go for seanizer's answer.