2009-06-30 17 views
6

Estoy escribiendo algunas herramientas para nuestro sistema de compilación para aplicar algunas convenciones de llamadas estrictas sobre métodos que pertenecen a clases que contienen ciertas anotaciones.Descubre la clase de una invocación de método en el procesador de anotaciones para java

estoy usando la API Compilador árbol ...

Lo que me pregunto es cuando se atraviesa el 'árbol', ¿cómo puede saber el tipo de clase/interfaz para un MethodInvocation.

estoy de subclases TreePathScanner con:

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

} 

estoy esperando theres una manera de contar el tipo de la clase (o interfaz) que usted está tratando de invocar el método en. ¿Voy por esto de la manera incorrecta? Gracias por cualquier idea ...

Respuesta

8

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.

+0

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

+0

Acabo de actualizar la entrada para explicar por qué los métodos devuelven nulo y cómo abordar ese – notnoop

+0

FYI, AbstractTypeProcessor ya no está disponible en compilaciones JDK 7, ya que se eliminó el soporte para JSR 308. –

Cuestiones relacionadas