Обработка аннотации Java 6 - получение класса из аннотации
У меня есть пользовательская аннотация, называемая @Pojo, которую я использую для создания автоматической вики-документации:
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();
}
Я использую его следующим образом:
@Pojo(com.example.restserver.model.appointment.Appointment.class)
для аннотации метода ресурса, чтобы обработчик аннотации мог автоматически генерировать страницу вики, описывающую ресурс и тип, который он ожидает.
Мне нужно прочитать значение поля value
в обработчике аннотаций, но я получаю ошибку времени выполнения.
В исходном коде для моего процессора у меня есть следующие строки:
final Pojo pojo = element.getAnnotation(Pojo.class);
// ...
final Class<?> pojoJavaClass = pojo.value();
но фактический класс недоступен для процессора. Думаю, мне нужен javax.lang.model.type.TypeMirror
вместо этого как суррогат для настоящего класса. Я не уверен, как его получить.
Ошибка, которую я получаю:
javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror com.example.restserver.model.appointment.Appointment
Appointment
- это класс, упомянутый в одной из моих аннотаций @Pojo
.
К сожалению, документация и/или учебники по обработке аннотации Java кажутся скудными. Пробовал поиск в Интернете.
Ответы
Ответ 1
Вы читали эту статью: http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/?
Там трюк состоит в том, чтобы фактически использовать getAnnotation() и уловить исключение MirroredTypeException. Неожиданно исключение предоставляет TypeMirror требуемого класса.
Я не знаю, является ли это хорошим решением, но оно одно. По моему личному мнению, я попытался бы получить тип за MirroredType, но я не знаю, возможно ли это.
Ответ 2
Я пришел сюда, чтобы задать ТОЧНЫЙ тот же вопрос.... и нашел ту же ссылку размещенную Ральфом.
Это длинная статья, но очень богатая. Резюме истории - есть два способа сделать это, простой способ и "более правильный" способ.
Это простой способ:
private static TypeMirror getMyValue1(MyAnnotation annotation) {
try
{
annotation.myValue(); // this should throw
}
catch( MirroredTypeException mte )
{
return mte.getTypeMirror();
}
return null; // can this ever happen ??
}
Другой более утомительный способ (без исключений):
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();
}
}
Конечно, как только вы получите TypeMirror, вы (по крайней мере, по моему опыту) почти всегда хотите TypeElement:
private TypeElement asTypeElement(TypeMirror typeMirror) {
Types TypeUtils = this.processingEnv.getTypeUtils();
return (TypeElement)TypeUtils.asElement(typeMirror);
}
... этот последний маленький неочевидный бит занял у меня час вытягивания волос, прежде чем я разобрал его в первый раз. Эти обработчики аннотаций на самом деле не так уж сложно писать, API просто сбивает с толку сначала и разумно многословно. Я соблазн выпустить класс-помощник, который делает все основные операции очевидными... но это история за другой день (если мне это нужно).