53

Suppose you have a text file like:

my_setting = ON
some_method = METHOD_A
verbosity = DEBUG
...

That you wish to to update a corresponding object accordingly:

Setting my_setting = ON;
Method some_method = METHOD_A;
Verbosity verbosity = DEBUG;
...

Where all are different kind of enums.

I would like to have a generic way to instantiate the enum values. That is, at runtime using reflection, and without knowing the enum types of the object in advance.

I would have imagined something like this:

for (ConfigLine line : lines)
{
   String[] tokens = line.string.split("=", 2);
   String name = tokens[0].trim();
   String value = tokens[1].trim();

   try
   {
      Field field = this.getClass().getDeclaredField(name);   
      if(field.getType().isEnum())
      {
         // doesn't work (cannot convert String to enum)
         field.set(this, value);
         // invalid code (some strange generics issue)
         field.set(this, Enum.valueOf(field.getType().getClass(), value));
      }
      else
      { /*...*/ }
   }
   catch //...
}

The question is: what should there be instead? Is it even possible to instantiate an unknown enum given its String representation?

Ben
  • 54,723
  • 49
  • 178
  • 224
dagnelies
  • 5,203
  • 5
  • 38
  • 56

5 Answers5

115
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value));
  • getClass() after getType() should not be called - it returns the class of a Class instance
  • You can cast Class<Enum>, to avoid generic problems, because you already know that the Class is an enum
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • this results in a generics compiler error: The method valueOf(Class, String) in the type Enum is not applicable for the arguments (Class, Object) – onejigtwojig Apr 25 '11 at 17:05
  • 11
    Would `field.getType().asSubclass(Enum.class)` be better? – Tom Anderson May 20 '12 at 23:03
  • 1
    This will have problems if you use declared fields - isEnumConstant may not work. Better to use valueOf method invocation as suggested by @rebzie – amrk7 Oct 05 '17 at 04:47
16

Alternative solution with no casting

try {
    Method valueOf = field.getType().getMethod("valueOf", String.class);
    Object value = valueOf.invoke(null, param);
    field.set(test, value);
} catch ( ReflectiveOperationException e) {
    // handle error here
}
Rebzie
  • 213
  • 2
  • 10
  • I think that this is the best solution for this question – allemattio Nov 28 '18 at 13:23
  • Just spent two hours trying to make selected answer work and couldn't because i didn't have the enum type to cast to - if only i scrolled down earlier... thank you – Quinn Oct 12 '19 at 03:43
5

You have an extra getClass call, and you have to cast (more specific cast per Bozho):

field.set(test, Enum.valueOf((Class<Enum>) field.getType(), value));
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
2

The accepted answer results in warnings because it uses the raw type Enum instead of Enum<T extends Enum<T>>.

To get around this you need to use a generic method like this:

@SuppressWarnings("unchecked")
private <T extends Enum<T>> T createEnumInstance(String name, Type type) {
  return Enum.valueOf((Class<T>) type, name);
}

Call it like this:

Enum<?> enum = createEnumInstance(name, field.getType());
field.set(this, enum);
Dev Vercer
  • 166
  • 1
  • 7
0

You may code your Enum similar tho this:

public enum Setting {

    ON("ON"),OFF("OFF");

    private final String setting;

    private static final Map<String, Setting> stringToEnum = new ConcurrentHashMap<String, Setting>();
    static {
        for (Setting set: values()){
            stringToEnum.put(set.setting, set);
        }
    }

    private Setting(String setting) {
        this.setting = setting;
    }

    public String toString(){
        return this.setting;
    }

    public static RequestStatus fromString(String setting){
        return stringToEnum.get(setting);
    }   
}

Then you may easily create Enum from String without reflection:

Setting my_settings = Setting.fromString("ON");

This solution is not originated from myself. I read it from somewhere else, but I can't recall the source.

ThiamTeck
  • 385
  • 1
  • 9
  • 3
    Not really helpful if you're using reflection, because you don't know if the enum in question is using this setup. – Kolky Oct 06 '10 at 08:54