Andrés Testi Hispano

Tuesday, October 10, 2006

Annotation Processing en JDK6 - Propuesta Final

En mi primer post tengo el agrado de comunicarles que fue recientemente liberada la proposición final de la especificación del Pluggable Annotation Processing. Para quienes jamás oyeron hablar de esta funcionalidad del JDK, voy a hacer un breve resúmen. Resulta que es posible hacer un preprocesamiento de annotations en tiempo de compilación, es decir, algo parecido a lo que hacemos con las macross de C, pero en una manera súmamente typesafe. Esta característica, nos brinda la posibilidad de generar clases auxiliares que luego serán utilizadas en tiempo de ejecución, a la vez que también nos permite realizar chequeos de consistencia sobre las annotations y lanzar warnings y/o errores de compilación. Con este nuevo artilugio, java podría posicionarse en el top de la metaprogramación, incluso por encima de lenguajes que hoy son venerados por los autodenominados programadores pragmáticos, como pueden ser Ruby y Python (es una pena que estos dos buenos lenguajes de script hayan engendrado toda esta generación de trolls).
La historia nos dice que el concepto de preprocesamiento en java comenzó con la misma aparición de las annotations, es decir en el JDK5, por medio del API denominado Annotation Processing Tool o APT (nombre muy mal elegido porque se presta a confusiones con el famoso comando Debian). Este API consiste en una serie de clases que nos permiten registrar "listeners" de procesamiento y, por medio del patrón Visitor (muy utilizado en los procesadores de XML), recorrer las declaraciones asociadas a cada annotation que queremos procesar. Las declaraciones nos llegan en la forma de metadatos, pero al ser estas analizadas en tiempo de compilación, no se utiliza la API Reflection, porque la misma supone la existencia de un entorno de ejecución. En cambio se utilizan unos objetos denominados Declarations, que representan declaraciones "textuales". Una vez que se tienen implementados y compilados estos procesadores, se utiliza el comando apt que preprocesa las clases objetivo con los procesadores de annotation que implementamos anteriormente. Hasta aquí he comentado lo que ocurre con APT en el JDK5, sin embargo en la documentación pertinente, SUN nos aconseja no encariñarnos con la actual especificación porque está sujeta a cambios. Y aquí es en donde entra en acción el JDK6, mejor conocido como Mustang. Por suerte, nuestros amigos se dieron cuenta de que no tenia sentido tener el comando apt por un lado y el javac por otro, y decidieron fundirlos en un único comando javac. Además, reordenaron el API que anteriormente se encontraba dentro de un paquete propietario, de los nunca bien ponderados com.sun, y lo introdujeron dentro de un subpaquete del javax. Con ésta nueva especificación, para registrar un procesador de annotations, simplemente debemos incluir una implementación de la clase AbstractProcessor dentro del classpath que utilizamos para compilar.
Para que mi explicación sea un poco más concreta, les muestro cómo se vería un procesador de annotations en JDK6:

import javax.annotation.processing.*;
import static  javax.lang.model.SourceVersion.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import java.util.Set;


// Indicamos que annotation queremos preprocesar.
// El '*' significa 'todas', como no podia ser de otra manera
@SupportedAnnotationTypes("*")

// Que version del JDK utilizamos?
@SupportedSourceVersion(RELEASE_6)

// Implementamos un nuevo procesador de annotations
public class HelloWorldProcessor extends AbstractProcessor {

// Este metodo es invocado cuando el compilador esta procesando
// una declaracion. RoundEnvironment contiene los metadatos asociados
// a la declaracion, ademas de un gestor de mensajes que nos permite
// emitir warnings y/o errores de compilacion
public boolean process(Set annotations,
RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()){
// hacemos que el compilador imprima un mensaje
processingEnv.getMessager().printNotice("Procesando una annotation");
}
return false;
}
}


El código anterior no tiene intenciones de abarcar el tema en profundidad, pero sirve para tener una idea de lo que estamos hablando.
Para variar, el concepto del preprocesamiento me parece fantástico, pero para mi gusto el API deja bastante que desear, sobre todo porque sólo permite evaluar declaraciones, y no expresiones o secuencias de código, que son los lugares en los que realmente sería útil.
Reconozco que sé poco del tema, pero creo que ésta capacidad permitiría extender el lenguaje de maneras nunca antes vistas. Por ejemplo, se podrían diseñar verdaderos frameworks de AOP autocontenidos, sin la necesidad de utilizar contenedores externos como el JBoss ni precompiladores como el AspectJ.
Sólo espero que perfeccionen el API para el JDK7, porque aún lo veo muy verde.

Más información:

- JSR-000269
- Blog del encargado del API
- Javadoc
- Minitutorial de APT en JDK5

9 Comments:

Post a Comment

<< Home