2017-06-18 1 views
0

Je veux analyser la variable de champ déclarée dans la classe MyComponent, et je veux obtenir le type GenericDeclartion de la classe de champ, pas le type il est déclaré dans MyComponent. La démo est ci-dessous.Comment obtenir le type de GenericDeclaration à partir de ParameterizedType à l'aide de Java Reflection?

public class SomeConfig<OP extends Operation> { 
    private OP operation; 

    public SomeConfig(OP op) { 
     this.operation = op; 
    } 
} 

public class MyComponent { 
    private SomeConfig<?> config; 

    public MyComponent(SomeConfig<?> config) { 
     this.config = config; 
    } 
} 

public class MyAnalysis { 
    public static void main(String[] args) { 
     Class clazz = MyComponent.class; 
     Field[] fields = clazz.getDeclaredFields(); 
     for (Field f : fields) { 
      Type type = f.getGenericType(); 
      if(type instanceof ParameterizedType) { 
       ParameterizedType pType = (ParameterizedType)type; 
       System.out.println(pType.getActualTypeArguments()[0]); // which prints "?" for sure 
      } 
     } 
    } 
} 

Le problème: Le résultat imprimé est "?" pour sûr. Mais tout ce que je veux, c'est d'imprimer le type de Operation au lieu de "?". Est-ce réalisable?

Répondre

3

Mais tout ce que je veux est d'obtenir le type d'opération

Generics sont effacées après la compilation, on ne pouvait pas y accéder de cette façon lors de l'exécution.

Pour atteindre votre besoin, vous pouvez changer le constructeur SomeConfig pour passer l'instance de classe du type paramétrées:

public class SomeConfig<OP extends Operation> { 
    private OP operation; 
    private Class<OP> clazz; 

    public SomeConfig(OP op, Class<OP> clazz) { 
     this.operation = op; 
     this.clazz = clazz; 
    } 
} 

Maintenant, le champ clazz peut être utilisé pour connaître la classe du type.

+0

Il y a aussi ['TypeToken'] (http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/reflect/TypeToken.html), plus précisément [ce constructeur] (http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/reflect/TypeToken.html#TypeToken-java.lang.Class-), mais 'TypeToken' n'est pas magie et peut ou peut ne pas fonctionner pour ce que le PO fait. 'TypeToken' a besoin d'un argument concret * non générique * (sinon' tt.getType() 'ne retournera pas' Class'), 2. une sous-classe, explicite ou implicite et 3. l'argument type fourni comme si à la clause 'extends' à la superclasse. – Radiodef

+0

Je ne connais pas bien la goyave. J'ai regardé plus en détail 'TypeToken'. 'TypeToken (Classe declaringClass)' semble faire la même chose: stocker l'instance de classe dans 'TypeToken' (pas de magie comme vous l'avez dit). Si je comprends bien, ça permet de faire la même chose mais sans ajouter le paramètre class au constructeur car la capture de type sera faite quand TypeToken est instancié dans la classe déclarante: 'new TypeToken (getClass())' ... – davidxxx

+0

.... Cela semble vraiment une bonne solution car cela ne dénature pas la signature constructeur de la classe générique. Cependant, ajouter une bibliothèque spécifique (qui ne peut pas être utilisée pour l'instant) et fournir une classe anonyme vide pour capturer le type (ce qui peut sembler surprenant lorsque vous lisez le code) est cependant un compromis à envisager. En tout cas merci pour cette information. Vraiment utile. – davidxxx