2012-07-08 24 views
23

Es posible que simplemente esté mirando en la dirección incorrecta, pero la documentación de JSE sobre el procesamiento de anotaciones me parece muy ... escasa. Quiero escribir un procesador de anotación que procese los campos de cadena anotados y las variables locales para sustituirlos por una expresión de cadena calculada. Esto no debería ser demasiado complicado, pero estoy bastante perdido en el Javadoc para javax.annotation.processing.Cómo escribir un procesador de anotación Java?

EDITAR: Necesito procesar las anotaciones en tiempo de compilación porque quiero modificar el código generado. Debería reemplazar las expresiones de cadena constantes anotadas con una expresión de cadena calculada.

+0

De acuerdo, mi punto de entrada era este tutorial: http://tutorials.jenkov.com/java-reflection/annotations.html –

+2

¿Desea procesar las anotaciones en tiempo de compilación o tiempo de ejecución? Tenga en cuenta que las anotaciones sobre las variables locales son en realidad inútiles debido a una limitación tonta de javac. –

+0

Quiero procesarlos en tiempo de compilación, por lo que obviamente solo funcionaría para expresiones de cadena constantes. –

Respuesta

14

Esto no se puede hacer con un procesador de anotación de tiempo de compilación. Los procesadores de anotación de tiempo de compilación solo pueden generar nuevos archivos (y clases) que no pueden modificar las clases existentes. Puede hacer la reflexión en tiempo de ejecución, pero hablando en términos estrictos, eso no se llama procesamiento de anotación. Además, no tendrá acceso a las variables locales.

Si usted está buscando sobre cómo escribir un procesador de anotación de tiempo de compilación echa un vistazo a https://github.com/pellaton/spring-configuration-validation-processor

+0

Teóricamente, podría usar un procesador de anotación + Apache BCEL (o algo similar) para modificar el archivo .class original. Pero eso suena desordenado. – vanza

+0

Err ... ¿qué? No puedo modificar el código fuente antes de la compilación utilizando el marco de anotación? –

+1

Miré el código vinculado. Obviamente no genera código, solo lo valida.Esperaba poder modificar el Árbol de sintaxis abstracta antes del paso de generación de código real. –

4
+0

He examinado Javassist y ASM. Tal vez harían el trabajo, pero se trata de la manipulación del código byte. Preferiría mucho usar una herramienta que me permita manipular el Árbol de sintaxis abstracta. La manipulación del código de bytes sería solo mi último recurso. –

+0

OK, después de investigar las opciones, parece que la única opción viable que queda es la manipulación del código byte. El próximo desafío es integrar esto en una versión de Maven, no solo para mí, sino también para los usuarios de mi biblioteca. –

+0

Hmm ... manipular AST sería mi último recurso :) –

8

Dos herramientas que hacen esto son Project Lombok y DuctileJ. Ambas herramientas existían en el momento en que se formuló originalmente la pregunta; herramientas adicionales ahora seguramente existen.

La idea clave es escribir un procesador de anotación que atraviese y modifique el AST del programa (árbol de sintaxis abstracta) durante la compilación, antes de la generación del código. El compilador no cambiará el código fuente en el disco, pero el archivo .class generado reflejará los cambios que realiza su procesador de anotación.

Puede adaptar una de estas herramientas a sus necesidades, o puede implementar su propia herramienta inspirada en sus técnicas de implementación.

El procesamiento en tiempo de compilación tiene dos ventajas sobre el procesamiento de archivos de clase. Una es que el compilador generalmente tiene más información de la disponible a partir del código compilado. Otra es que todo sucede en un solo paso, durante la compilación, en lugar de requerir que el desarrollador ejecute una herramienta por separado para reescribir los archivos .class después de la compilación.

+0

seguro, y vale la pena mencionar que ambos usan un truco para modificar el AST, explotando un error en el procesador de anotación actual en Java, haciendo uso de API javac internas que podrían ser arreglado/eliminado en algún futuro JDK (lo cual es una gran desventaja para mí). –

Cuestiones relacionadas