Hay un par de problemas aquí. Puede estar interesado en conociendo el tipo de Java del receptor de invocación de método o simplemente sabiendo que se invoca la clase en el método. La información de Java es más informativa, ya que también le proporciona tipos genéricos, p. List<String>
mientras que Elements solo le proporcionará la clase, p. List<E>
.
Conseguir el elemento
Para obtener el elemento de la clase del método se invoca en, puede hacerlo lo siguiente:
MethodInvocationTree node = ...;
Element method =
TreeInfo.symbol((JCTree)node.getMethodSelect());
TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
casos de esquina:
1. invookedClass podría ser una superclase del tipo de receptor. Entonces, ejecutar el fragmento de new ArrayList<String>.equals(null)
volvería AbstractList
en lugar de ArrayList
, ya que los iguales() se implementa en AbstractList
no ArrayList
.
2. Al manejar las invocaciones de matriz, p. new int[].clone()
, podría obtener TypeElement
de la clase Array
.
Conseguir el tipo real
Para obtener el tipo, no hay manera directa para determinar que lo que el tipo de receptor es . Existe cierta complejidad en el manejo de las invocaciones de métodos dentro de las clases internas donde el receptor no se proporciona explícitamente (por ejemplo, a diferencia de OuterClass.this.toString()
). Aquí es un ejemplo de implementación:
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());
Nota:
El tipo receiver
es necesario que haya TypeMirror
no DeclaredType
por desgracia. Al llamar al new int[5].clone()
, receiver
sería un ArrayType
de int[]
, que es más informativo que el método anterior .
conseguir que se ejecute
Los dos métodos anteriores requieren el compilador para resolver la información de tipo para las clases. En circunstancias normales, el compilador solo resuelve los tipos de declaraciones de métodos pero no los cuerpos. Por lo tanto, los métodos descritos anteriormente devolverían null
en su lugar.
Para que el compilador resuelve la información de tipo, se puede realizar una de las siguientes maneras :
1. Uso AbstractTypeProcessor
clase que acaba de ser añadido al repositorio compilador para JDK 7. Mira la obra en JSR 308 y su compilador. Si bien el trabajo se basa principalmente en tipos anotados, podría ser útil para. El compilador le permite utilizar la clase provisto de una manera compatible con versiones anteriores Java 5.
Este enfoque permite escribir procesadores que consiguen invoca justo como sus procesadores actuales.
2. En su lugar, utilice JavacTask
y llame al JavacTask.analyze()
. Mire el método principal de this javac test para ver cómo para invocar a su visitante en las clases.
Este enfoque hace que su procesador se parezca más a una herramienta de análisis que a un complemento del compilador, ya que tendría que invocarlo directamente en lugar de tenerlo como un proceso normal.
Gracias por la respuesta. Sin embargo, la línea: Element method = TreeInfo.symbol ((JCTree) node.getMethodSelect()); devuelve nulo para mí. \t TypeMirror m = trees.getTypeMirror (ruta); también devuelve nulo, al igual que \t TypeElement e = (TypeElement) trees.getElement (ruta); ¿Estoy cometiendo un error de novato y olvidándome de inicializar algo, o llamando/anulando el método incorrecto, o subclasando algo incorrecto? Gracias de nuevo por su ayuda ... – runT1ME
Acabo de actualizar la entrada para explicar por qué los métodos devuelven nulo y cómo abordar ese – notnoop
FYI, AbstractTypeProcessor ya no está disponible en compilaciones JDK 7, ya que se eliminó el soporte para JSR 308. –