2010-09-17 11 views
36

Załóżmy, że masz plik tekstowy jak:Java: instancji enum przy użyciu odbicia

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

który chcesz zaktualizować odpowiedni obiekt Odpowiednio:

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

Gdzie wszyscy są różnego rodzaju teksty stałe .

Chciałbym mieć ogólny sposób tworzenia wartości wyliczeniowych. Oznacza to, że w środowisku wykonawczym używa się refleksji i bez znajomości typów obiektów z wyprzedzeniem.

bym sobie wyobrazić coś takiego:

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 //... 
} 

pytanie brzmi: jakie powinny być tam zamiast tego? Czy możliwe jest nawet utworzenie nieznanego wyliczenia z uwzględnieniem jego reprezentacji String?

Odpowiedz

80
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value)); 
  • getClass() po getType() nie powinien być nazywany - zwraca Klasy Class instancja
  • Możesz rzucić Class<Enum>, aby uniknąć ogólnych problemów, ponieważ wiesz już, że Class to enum
+0

rodzajowych Phunky! (8 kolejnych) –

+0

Powoduje to błąd generycznego kompilatora: Metoda valueOf (klasa , ciąg) w typie Enum nie ma zastosowania do argumentów (klasa , obiekt) – onejigtwojig

+0

Jaki kompilator? .. – Bozho

4

Masz dodatkowy getClass połączenia, a masz do oddania (bardziej konkretny obsady za Bozho):

field.set(test, Enum.valueOf((Class<Enum>) field.getType(), value)); 
+1

problem nadal występuje – Bozho

0

Możesz kodzie Enum podobny Chciaż to:

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); 
    } 
} 

Wtedy może łatwo tworzyć Enum z String bez refleksji:

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

To rozwiązanie nie pochodzi od siebie. Czytam to gdzie indziej, ale nie mogę sobie przypomnieć źródła.

+0

Niezbyt pomocne, jeśli używasz refleksji, ponieważ nie wiesz, czy dany enum używa tej konfiguracji. – Kolky

2

Alternatywne rozwiązanie bez odlewania

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 
} 
0

Przyjęte Wyniki odpowiedź w ostrzeżeniach, ponieważ używa surowego typu Enum zamiast Enum < T rozciąga Enum <T> >.

Aby obejść ten problem trzeba użyć metody rodzajowe tak:

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

Nazwijmy to tak:

Enum<?> enum = createEnumInstance(name, field.getType()); 
field.set(this, enum); 
Powiązane problemy