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?
valueOf() method returns the enum constant of the specified enumtype with the specified name. The name must match exactly an identifier used to declare an enum constant in this type.
valueOf(Class<T> enumType, String name) Returns the enum constant of the specified enum type with the specified name.
Values() and valuesOf() methods The values() method returns an array that contains a list of the enumeration constants and the valueOf() method returns the enumeration constant whose values corresponds to the string passed in str.
No they cannot. They are limited to numeric values of the underlying enum type.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With