2011-10-07 26 views
35

tengo una anotación personalizada llamada @Pojo que utilizo para la generación automática de documentación wiki:Java procesamiento 6 de anotación - conseguir una clase desde una anotación

package com.example.annotations; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.METHOD) 
public @interface Pojo { 
    Class<?> value(); 
} 

lo uso como esto:

@Pojo(com.example.restserver.model.appointment.Appointment.class) 

para anotar un método de recursos para que el procesador de anotaciones pueda generar automáticamente una página wiki que describa el recurso y el tipo que espera.

Necesito leer el valor del campo value en un procesador de anotación, pero obtengo un error de tiempo de ejecución.

En el código fuente de mi procesador Tengo las siguientes líneas:

final Pojo pojo = element.getAnnotation(Pojo.class); 
// ... 
final Class<?> pojoJavaClass = pojo.value(); 

pero la clase real en no disponible para el procesador. Creo que necesito un javax.lang.model.type.TypeMirror en lugar de un sustituto para la clase real. No estoy seguro de cómo conseguir uno.

El error que estoy consiguiendo es:

javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror com.example.restserver.model.appointment.Appointment 

El Appointment es una clase mencionada en uno de mis @Pojo anotación.

Desafortunadamente, el documento y/o tutoriales sobre el procesamiento de anotaciones Java parece escaso. Intenté googlear.

+1

No muchas personas hacen este tipo de preguntas, pero para aquellos de nosotros que vivimos en el (Java) Tartarus, el apoyo de otros resulta ser muy útil – Ordiel

Respuesta

20

Has leído este artículo: http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/?

El truco consiste en utilizar getAnnotation() y atrapar la MirroredTypeException. Sorprendentemente, la excepción proporciona el TypeMirror de la clase requerida.

No sé si esta es una buena solución, pero es una. En mi opinión personal trataría de obtener el tipo detrás del MirroredType, pero no sé si esto es posible.

+1

Eso puede ser el truco, aunque "cinta adhesiva y goma de mascar" se me ocurre. Por cierto, genial nombre de usuario :-). – Ralph

32

Vine aquí para hacer la EXACTA la misma pregunta. ... y encontró el mismo blog link publicado por Ralph.

Es un artículo largo, pero muy rico. Resumen de la historia: hay dos formas de hacerlo, la manera fácil y la manera "más correcta".

Este es el camino más fácil:

private static TypeMirror getMyValue1(MyAnnotation annotation) { 
    try 
    { 
     annotation.myValue(); // this should throw 
    } 
    catch(MirroredTypeException mte) 
    { 
     return mte.getTypeMirror(); 
    } 
    return null; // can this ever happen ?? 
} 

La otra forma más tedioso (sin excepciones):

private static AnnotationMirror getAnnotationMirror(TypeElement typeElement, Class<?> clazz) { 
    String clazzName = clazz.getName(); 
    for(AnnotationMirror m : typeElement.getAnnotationMirrors()) { 
     if(m.getAnnotationType().toString().equals(clazzName)) { 
      return m; 
     } 
    } 
    return null; 
} 

private static AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String key) { 
    for(Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror.getElementValues().entrySet()) { 
     if(entry.getKey().getSimpleName().toString().equals(key)) { 
      return entry.getValue(); 
     } 
    } 
    return null; 
} 


public TypeMirror getMyValue2(TypeElement foo) { 
    AnnotationMirror am = getAnnotationMirror(foo, MyAnnotation.class); 
    if(am == null) { 
     return null; 
    } 
    AnnotationValue av = getAnnotationValue(am, "myValue"); 
    if(av == null) { 
     return null; 
    } else { 
     return (TypeMirror)av.getValue(); 
    } 
} 

Por supuesto, una vez que llegue un TypeMirror, que (al menos en mi experiencia) casi siempre quieren un lugar TypeElement:

private TypeElement asTypeElement(TypeMirror typeMirror) { 
    Types TypeUtils = this.processingEnv.getTypeUtils(); 
    return (TypeElement)TypeUtils.asElement(typeMirror); 
} 

... que poco pasado no obvia me tomó una hora de tirar del pelo antes de que lo resolviera la primera vez. Estos procesadores de anotaciones en realidad no son tan difíciles de escribir, las API son muy confusas al principio y extremadamente detalladas.Estoy tentado de crear una clase de ayuda que haga que todas las operaciones básicas sean obvias ... pero esa es una historia para otro día (cómprame si quieres).

+0

Estoy atrapado aquí también. ¿Podrías publicar una esencia con tu ayudante si hicieras alguna, por favor? – gorodechnyj

+1

@gorodechnyj - aquí está el código que estaba escribiendo en ese momento: https://github.com/ddopson/EpicFramework/blob/uiv2/EpicBuilder/src/com/epic/framework/build/EpicAnnotationProcessor.java Siéntase libre de cavar a través de y robar liberalmente –

Cuestiones relacionadas