2009-06-30 9 views
6

J'écris des outils pour que notre système de construction applique des conventions d'appel strictes sur les méthodes appartenant à des classes contenant certaines annotations.Découvrez la classe d'un methodinvocation dans le processeur d'annotation pour Java

J'utilise l'API arbre compilateur ...

Ce que je me demande est en traversant le « arbre », comment pouvez-vous dire le type de classe/interface pour un MethodInvocation.

Je TreePathScanner avec le sous-classement:

@Override 
public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) { 

} 

J'espère Theres une façon de dire le type de la classe (ou interface) que vous essayez d'invoquer la méthode sur. Est-ce que je vais à ce sujet dans le mauvais sens? Merci pour vos idées ...

Répondre

8

Il y a quelques problèmes ici. Vous pouvez soit être intéressé par en connaissant le type Java du récepteur d'invocation de méthode ou simplement en sachant que la classe sur la méthode est invoquée. Les informations Java sont plus informatives car elles vous donnent également des types génériques, par ex. List<String> tandis que les éléments ne vous fournissaient que la classe, par ex. List<E>.

Obtenir l'élément

Pour obtenir l'élément de la classe la méthode est invoquée, vous pouvez faire les éléments suivants:


    MethodInvocationTree node = ...; 
    Element method = 
     TreeInfo.symbol((JCTree)node.getMethodSelect()); 
    TypeElement invokedClass = (TypeElement)method.getEnclosingElement(); 

cas d'angle:

1. invokedClass peut être une super-classe du type de récepteur. Donc, en cours d'exécution l'extrait sur new ArrayList<String>.equals(null) retournerait AbstractList plutôt que ArrayList, puisque equals() est mis en œuvre dans AbstractList pas ArrayList.

2. Lors de la gestion des appels de réseau, par ex. new int[].clone(), vous obtiendriez obtenir TypeElement de la classe Array.

Obtenir le type réel

Pour obtenir le type, il n'y a aucun moyen direct pour déterminer ce que le type de récepteur est . Il y a une certaine complexité dans la gestion des invocations de méthodes dans des classes internes où le récepteur n'est pas donné explicitement (par exemple, contrairement à OuterClass.this.toString()). Voici un exemple d'implémentation:


    MethodInvocationTree node = ...; 
    TypeMirror receiver; 
    if (methodSel.getKind() == Tree.Kind.MEMBER_SELECT) { 
    ExpressionTree receiver = ((MemberSelectTree)methodSel).getExpression(); 
    receiverType = ((JCTree)receiver).type; 
    } else if (methodSel.getKind() == Tree.Kind.IDENTIFIER) { 
    // need to resolve implicit this, which is described in 
    // JLS3 15.12.1 and 15.9.2 

    // A bit too much work that I don't want to work on now 
    // Look at source code of 
    // Attr.visitApply(JCMethodInvocation) 
    // resolveImplicitThis(DiagnosticPosition, Env, Type) 
    } else 
    throw new AssertionError("Unexpected type: " + methodSel.getKind()); 

Note:

Le type receiver doit être TypeMirror pas DeclaredType malheureusement. Lors de l'appel new int[5].clone(), receiver serait un ArrayType de int[], ce qui est plus informatif que la précédente méthode .

Obtenir à exécuter

Les deux méthodes précédentes exigent le compilateur pour résoudre les informations de type pour les classes. Dans les circonstances habituelles, le compilateur résout uniquement les types pour les déclarations de méthode mais pas les corps. Par conséquent, les méthodes décrites précédemment retourneront null à la place.

Pour avoir le compilateur résoudre les informations de type, vous pouvez faire l'une des façons suivantes:

1. Utilisez la classe AbstractTypeProcessor qui vient de s'ajouter au dépôt du compilateur pour JDK 7. Vérifiez les travaux sur JSR 308 et leur compilateur. Alors que le travail est principalement sur les types annotés, il pourrait être utile pour. Le compilateur vous permet d'utiliser la classe fournie d'une manière compatible avec Java arrière 5.

Cette approche vous permet d'écrire des processeurs qui s'invoquaient juste comme vos processeurs actuels.

2. Utilisez plutôt JavacTask et appelez JavacTask.analyze(). Regardez la méthode principale de this javac test pour voir comment pour invoquer votre visiteur sur les classes. Cette approche fait de votre processeur un outil d'analyse plutôt qu'un plug-in pour le compilateur, car vous devez l'appeler directement plutôt que d'avoir un processus normal.

+0

Merci pour la réponse. Toutefois, la ligne: Méthode d'élément = TreeInfo.symbol ((JCTree) node.getMethodSelect()); renvoie null pour moi. \t TypeMiroir m = trees.getTypeMirror (chemin); renvoie également la valeur null, de même que \t TypeElement e = (TypeElement) trees.getElement (chemin); Est-ce que je fais une erreur de débutant et que j'oublie d'initialiser quelque chose, ou d'appeler/de passer outre la mauvaise méthode, ou de sous-classer quelque chose de mal? Merci encore pour votre aide ... – runT1ME

+0

Je viens de mettre à jour l'entrée pour expliquer pourquoi les méthodes renvoient null et comment adresser cela – notnoop

+0

FYI, AbstractTypeProcessor n'est plus disponible dans les versions JDK 7, puisque le support pour JSR 308 a été abandonné. –

Questions connexes