views:

75

answers:

3

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?

A: 

Try to use named generic parameter instead of "?" (same in lines 2 and 3). Like this:

Class<T extends Enum<T>> ...
Enum<T> ...  or simply T enumValue = ...
manuna
That only works in method declarations, not in a code body... Doesnt it??
Tom
Have you tried that yourself? Does that compile for you??
Tom
@manuna: please spell out your code. I doubt very much that this will compile so I'd like to verify that you mean what I think you mean.
seanizer
Sorry, Tom is right - this works in method declarations, not in method body. But the idea was the same as "Tom Hawtin - tackline" wrote - about distinct wildcards
manuna
+1  A: 

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

seanizer
The question is about enums, generics and reflection. If you ignore generics, what's the point? Particularly going for "rare types" like `Class<? extends Enum>`.
Tom Hawtin - tackline
The 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 satisfy `Class<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.
seanizer
A: 

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.

Tom Hawtin - tackline
Thanks 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.
Tom