2010-09-17 6 views
36

Supposons que vous ayez un fichier texte comme:Java: instanciation d'un ENUM utilisant la réflexion

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

que vous souhaitez mettre à jour un objet correspondant en conséquence:

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

Où sont tous les différents types de énumérations .

Je voudrais avoir une façon générique d'instancier les valeurs enum. C'est-à-dire, à l'exécution en utilisant la réflexion, et sans connaître les types d'énumération de l'objet à l'avance.

je l'aurais imaginé quelque chose comme ceci:

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

La question est: que doit-il être à la place? Est-il même possible d'instancier une énumération inconnue compte tenu de sa représentation sous forme de chaîne?

Répondre

80
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value)); 
  • getClass() après getType() ne doit pas être appelée - elle renvoie la classe d'un Class instance
  • Vous pouvez lancer Class<Enum>, pour éviter les problèmes génériques, car vous savez déjà que le Class est un enum
+0

Phunky! (8 plus à aller) –

+0

il en résulte une erreur de compilation générique: La méthode valueOf (Classe , String) dans le type Enum n'est pas applicable pour les arguments (Classe , Object) – onejigtwojig

+0

Quel compilateur? .. – Bozho

4

Vous avez un getClass appel, et vous devez jeter (fonte plus spécifique par Bozho) supplémentaire:

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

le problème des génériques se produit encore – Bozho

0

Vous peut coder votre Enum même tho ceci:

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

Ensuite, vous pouvez facilement créer Enum de chaîne sans réflexion:

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

Cette solution est de moi-même ne proviennent pas. Je l'ai lu ailleurs, mais je ne me souviens pas de la source.

+0

Pas vraiment utile si vous utilisez la réflexion, car vous ne savez pas si l'énumération en question utilise cette configuration. – Kolky

2

solution alternative sans coulée

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

Les résultats de réponse acceptée dans les avertissements, car il utilise le type brut Enum au lieu de Enum < T étend Enum <T> >.

Pour contourner cela, vous devez utiliser une méthode générique comme ceci:

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

Appelez comme ceci:

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