2017-09-01 3 views
0

J'ai un ENUM avec classe interne anonyme comme:Java enum classe interne anonyme et de réflexion

public enum Status { 

    PRELIMINARY() { 
    @Override 
    boolean process() { 
     return true; 
    } 

    SUBMITTED() { 
    @Override 
    boolean process() { 
     return false; 
    } 

    abstract boolean process(); 

} 

J'ai un modèle comme

public class Foo { 

    private Status status; 

    public void setStatus(Status status) { 
     this.status = status; 
    } 
} 

je dois utiliser la réflexion pour définir un Foo.status comme:

private static <T> void setFieldValue(Foo instance, Class<?> klazz, Object value) { 
    try { 
     Class<?> aClass = value.getClass(); // Is Status$1 instead of Status 
     Method method = klazz.getDeclaredMethod(getSetterName('setStatus'), aClass); 
     method.invoke(instance, value); 
    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { 
     if (!klazz.equals(Object.class)) { 
      setFieldValue(instance, klazz.getSuperclass(), fieldName, value); 
     } 
    } 
} 

Cela fonctionne lorsque Status ne contient pas une classe interne et est enum simple, cependant pour la classe Status ci-dessus, il va jeter un NoSuchMethodException. C'est parce que la classe de ma valeur sera package.Status$1 au lieu de package.Status.

Y a-t-il un bon travail pour cela?

+0

Pour ne pas être trop pointilleux, mais votre code d'exemple manque des parenthèses et votre exemple de réflexion semble complètement non pertinent car il n'y a aucune méthode qui pourrait correspondre à l'invocation. – Dave

+0

Merci Dave, j'ai mis à jour mon code pour mieux refléter mon problème. – pez

+0

[Cette réponse] (https://stackoverflow.com/a/45590933/2891664) pourrait vous aider. Cependant, je me demande pourquoi exactement vous utilisez la réflexion ici, puisque vous semblez en savoir beaucoup sur la méthode que vous invoquez à l'avance. – Radiodef

Répondre

1

Vous avez juste besoin de changer vos moyens de localiser la méthode désirée. Quelque chose comme ce qui suit devrait fonctionner:

private static @Nullable Method findMethod(Class<?> klass, 
              final String methodName, 
              final Object... args) { 

    @Nullable Method candidate = null; 

    classSearch: 
    while (klass != null) { 

     // Check all the class' methods for a matching one. 
     methodSearch: 
     for (final Method method : klass.getDeclaredMethods()) { 
      if (!method.getName().equals(methodName)) continue; 

      final Class<?>[] parameterTypes = method.getParameterTypes(); 
      if (parameterTypes.length != args.length) continue; 

      // Check all parameters can come from the given args. 
      for (int i = 0; i < args.length; i++) { 
       if (!parameterTypes[i].isInstance(args[i])) continue methodSearch; 
      } 

      candidate = method; 
      break classSearch; 
     } 

     // No matching method, check super class. 
     klass = klass.getSuperclass(); 
    } 

    // May be 'null' if no match was found. 
    // Throw an Exception if this isn't a valid outcome in your case. 
    return candidate; 
} 

Chaînage avec votre code existant (appelant .invoke sur le retour Method (si ce n'est pas null)) devrait vous donner le résultat souhaité.