Découvrez la classe d'un methodinvocation dans le processeur d'annotation pour Java
-
21-08-2019 - |
Question
Je suis en train d'écrire des outils pour notre système de construction pour faire respecter certaines conventions d'appel strictes sur les méthodes appartenant à des classes contenant certaines annotations.
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 suis avec le sous-classement TreePathScanner:
@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 sur ce dans le mauvais sens? Merci pour toutes les idées ...
La solution
Il y a quelques problèmes ici. Vous pouvez être intéressé par
connaître le type Java du récepteur d'appel de méthode ou juste
sachant la classe sur la méthode est invoquée. Java est plus d'informations
d'information car il vous donne les types génériques ainsi, par exemple List<String>
tandis que les éléments ne ferait que vous fournir la classe, par exemple List<E>
.
Obtenir l'élément
Pour obtenir l'élément de la classe la méthode est invoquée, vous pouvez le faire ce qui suit:
MethodInvocationTree node = ...;
Element method =
TreeInfo.symbol((JCTree)node.getMethodSelect());
TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
cas d'angle:
1.
invokedClass pourrait être une superclasse du type de récepteur. Donc, en cours d'exécution
l'extrait sur retournerait new ArrayList<String>.equals(null)
Plutôt que AbstractList
ArrayList
, puisque equals () est mis en œuvre
en ne new int[].clone()
TypeElement
.
2.
Lors de la manipulation des invocations de matrice, par exemple Array
, vous le feriez
obtenir de la classe OuterClass.this.toString()
receiver
.
Obtenir le type réel
Pour obtenir le type, il n'y a aucun moyen direct pour déterminer ce que la
type de récepteur est. Il y a une certaine complexité dans le traitement des invocations de méthode
dans les classes internes où le récepteur n'est pas donné explicitement
(Par exemple, contrairement à TypeMirror
). Voici une 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 DeclaredType
type doit être pas new int[5].clone()
ArrayType
malheureusement. Lors de l'appel int[]
, serait null
un de AbstractTypeProcessor
JavacTask
, qui est plus informatif que le précédent
méthode.
Comment à exécuter
Les deux méthodes précédentes exigent le compilateur pour résoudre le type
informations pour les classes. Dans des circonstances habituelles, le compilateur
seulement résoudre les types de déclarations de méthode mais pas les organismes.
Par conséquent, les méthodes décrites précédemment retourneraient à la place JavacTask.analyze()
.
Pour que le compilateur résoudre les informations de type, vous pouvez faire l'une des de la manière suivante:
1. Utilisez la classe qui vient <=> se est ajouté à la dépôt de 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. Le compilateur vous permet d'utiliser la classe prévue dans une arrière de manière compatible avec Java 5.
Cette approche vous permet d'écrire des processeurs qui s'invoquaient juste comme vos processeurs actuels.
2. Utilisez plutôt appeler et <=> <=>. Regarder la principale méthode de ce test javac pour voir comment pour appeler votre visiteur sur les classes.
Cette approche rend votre processeur plus comme un outil d'analyse plutôt que d'un plug-in pour le compilateur, comme vous devez l'appeler directement plutôt que de l'avoir un processus régulier.