2010-09-17 9 views
36

Angenommen, Sie eine Textdatei haben wie:Java: Instanziieren eine Enumeration mit Reflexion

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

Dass Sie wollen demnach ein entsprechendes Objekt zu aktualisieren:

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

Wo alle andere Art von Aufzählungen sind .

Ich möchte eine generische Möglichkeit haben, die Enum-Werte zu instanziieren. Das heißt, zur Laufzeit mit Reflektion und ohne vorher die Enum-Typen des Objekts zu kennen.

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

Die Frage ist: was sollte es stattdessen sein

ich so etwas wie dies hätte gedacht? Ist es überhaupt möglich, eine unbekannte Enumeration in ihrer String-Repräsentation zu instanziieren?

Antwort

80
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value)); 
  • getClass() nach getType() nicht aufgerufen werden soll - es die Klasse der ein zurück Class Instanz
  • Sie können Class<Enum>, um generische Probleme zu vermeiden, weil Sie bereits wissen, dass die Class ist ein enum
+0

Phunky! (8 mehr zu gehen) –

+0

Dies führt zu einem Generics-Compiler-Fehler: Die Methode valueOf (Klasse , String) im Typ Enum ist nicht anwendbar für die Argumente (Klasse , Object) – onejigtwojig

+0

Welcher Compiler? .. – Bozho

4

Sie haben einen zusätzlichen getClass Anruf, und Sie haben zu werfen (spezifischere Guss pro Bozho):

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

das Generika Problem weiterhin auftritt – Bozho

0

Sie können Ihre Enum ähnlich tho diesen Code:

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

Dann können Sie leicht Enum von String erstellen, ohne Reflexion:

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

Diese Lösung ist nicht von mir stammt. Ich habe es von woanders gelesen, aber ich kann mich nicht an die Quelle erinnern.

+0

Nicht wirklich hilfreich, wenn Sie Reflektion verwenden, weil Sie nicht wissen, ob das Enum in Frage dieses Setup verwendet. – Kolky

2

Alternative Lösung ohne 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 
} 
0

Die akzeptierte Antwort führt zu Warnungen, weil es verwendet den rohen Typ Enum statt Enum < T erweitert Enum <T> >.

Um dies zu umgehen Sie eine generische Methode wie folgt verwenden müssen:

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

es so Aufruf:

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