Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the value of an Enum, if I don't know the class at compile time?

I'm trying to do the following:

Class<?> cls = unknownClass;
if(cls.isEnum()){
    @SuppressWarnings("unchecked")
    Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) cls;
    Object val = Enum.valueOf(enumClass, "NAME1");
}

But I get the following error:

Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is 
not applicable for the arguments (Class<capture#5-of ? extends Enum<?>>, String). 
The inferred type capture#5-of ? extends Enum<?> is not a valid substitute for 
the bounded parameter <T extends Enum<T>>   

Can someone tell me what I am doing wrong?

like image 430
cammil Avatar asked Mar 10 '11 15:03

cammil


People also ask

How do I view enum outside class?

You have to declare enum as public ... (depend on what you want) and then use class name as prefix when outside package. @RongNK - It doesn't have to be public ; if its in the same package, it can have default access. You need to use the class name as a prefix even within the same package unless you import the enum.

Can we get an enum by value?

Get the value of an EnumTo get the value of enum we can simply typecast it to its type. In the first example, the default type is int so we have to typecast it to int. Also, we can get the string value of that enum by using the ToString() method as below.


3 Answers

Given that the cast won't really be checking things, I'd go with the completely raw version:

if (cls.isEnum()){
    @SuppressWarnings("unchecked")
    Object val = Enum.valueOf(cls, "NAME1");
}

That seems to work. Complete example:

public class Test
{
    enum Foo
    {
        BAR, BAZ
    }


    public static void main(String[] args)
    {
        @SuppressWarnings("rawtypes")
        Class cls = Foo.class;

        if (cls.isEnum())
        {        
            @SuppressWarnings("unchecked")
            Object value = Enum.valueOf(cls, "BAR");
            System.out.println(value);
        }
    }
}
like image 148
Jon Skeet Avatar answered Oct 16 '22 07:10

Jon Skeet


The problem is that you have two ? and they could be different and they have to be the same.

You either have to use a non generic of declare a generic type like

public static <T extends Enum<T>> T val(Class<T> cls) {
    if(cls.isEnum()) { // is redundant when the compiler checks this.
        @SuppressWarnings("unchecked")
        Class<T> enumClass = (Class<T>) cls;
        T val = Enum.valueOf(enumClass, "NAME1");
        return val;
    }
    return null;
}

However, calling this method is a bit of a nightmare as well. ;)

like image 24
Peter Lawrey Avatar answered Oct 16 '22 08:10

Peter Lawrey


Class.getEnumConstants will give all the enums, which you can then find the one you are interested in.

Modifying Jon's code:

public class Test {
    private enum Foo {
        BAR, BAZ
    } 

    public static void main(String[] args) {
        Class<?> cls = Foo.class;

        if (cls.isEnum()) { 
            for (Object constant : cls.getEnumConstants()) { 
                Enum<?> enumConstant = (Enum<?>)constant;
                if (enumConstant.name().equals("BAR")) {
                    System.out.println(constant);
                    break;
                }
            }
        }
    }
}

In Java SE 8, you'll possibly be able do something clever with a lambda and abstracted control flow.

Note:

  • Reflection is almost always a really bad idea.
  • No need for unchecked warning or suppression of those valid warnings.
  • No need for rawtypes (which ever spelling and semantics) warning or suppression of those valid warnings.
  • No need for an unfounded rant.
  • No need to downvote this answer.
like image 27
Tom Hawtin - tackline Avatar answered Oct 16 '22 09:10

Tom Hawtin - tackline