我正在编写我的第一个注释处理器,但遇到一些琐碎的问题,但找不到任何有关它的信息。
我有一个带有注释的元素
@MyAnnotation String property;
当我将此属性作为处理器中的元素获取时,我似乎无法以任何方式获取元素的类型。在这种情况下,可能要获取代表String的Class或TypeElement实例。
我尝试使用实例化容器类型的类对象,Class.forName()但它引发了ClassNotFoundException。我认为这是因为我无法访问包含该类的类加载器吗?
Class.forName()
运行注释处理器时,您无权访问已编译的类。注释处理的要点是它发生在预编译中。
相反,您需要创建一个专门处理您的注释类型的注释处理器,然后使用镜像API来访问该字段。例如:
@SupportedAnnotationTypes("com.example.MyAnnotation") public class CompileTimeAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // Only one annotation, so just use annotations.iterator().next(); Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith( annotations.iterator().next()); Set<VariableElement> fields = ElementFilter.fieldsIn(elements); for (VariableElement field : fields) { TypeMirror fieldType = field.asType(); String fullTypeClassName = fieldType.toString(); // Validate fullTypeClassName } return true; } }
为了进行验证,您 不能 使用诸如之类的任何尚未编译的类(包括即将通过注释编译的类)MyType.class。对于这些,您 只能 使用 字符串 。那是因为注释处理发生在称为“源生成”的预编译阶段,这使您可以在编译器使用注释运行之前生成源代码。
MyType.class
验证字段类型为java.lang.String(已编译)的示例验证:
java.lang.String
for (VariableElement field : fields) { TypeMirror fieldType = field.asType(); String fullTypeClassName = fieldType.toString(); if (!String.class.getName().equals(fullTypeClassName)) { processingEnv.getMessager().printMessage( Kind.ERROR, "Field type must be java.lang.String", field); } }
资源资源
javax.lang.model
javax
编辑:
我想获取字段类型以获取对该类型的注释。但这似乎不可行吗?
确实有可能!可以使用以下更多方法来完成此操作TypeMirror:
TypeMirror
if (fieldType.getKind() != TypeKind.DECLARED) { processingEnv.getMessager().printMessage( Kind.ERROR, "Field cannot be a generic type.", field); } DeclaredType declaredFieldType = (DeclaredType) fieldType; TypeElement fieldTypeElement = (TypeElement) declaredFieldType.asElement();
在这里,您有两种选择:
javac
AnnotationMirror
已经编译
DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation( DifferentAnnotation.class); // Process diffAnn
非常简单,这使您可以直接访问注释本身。
未编译
请注意,无论注释是否被编译,该解决方案都将起作用,它不如上面的代码那么干净。
这是我曾经编写的几个方法,用于通过其类名称从注释镜像中提取特定值:
private static <T> T findAnnotationValue(Element element, String annotationClass, String valueName, Class<T> expectedType) { T ret = null; for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { DeclaredType annotationType = annotationMirror.getAnnotationType(); TypeElement annotationElement = (TypeElement) annotationType .asElement(); if (annotationElement.getQualifiedName().contentEquals( annotationClass)) { ret = extractValue(annotationMirror, valueName, expectedType); break; } } return ret; } private static <T> T extractValue(AnnotationMirror annotationMirror, String valueName, Class<T> expectedType) { Map<ExecutableElement, AnnotationValue> elementValues = new HashMap<ExecutableElement, AnnotationValue>( annotationMirror.getElementValues()); for (Entry<ExecutableElement, AnnotationValue> entry : elementValues .entrySet()) { if (entry.getKey().getSimpleName().contentEquals(valueName)) { Object value = entry.getValue().getValue(); return expectedType.cast(value); } } return null; }
假设您正在寻找DifferentAnnotation注释,并且您的源代码如下所示:
DifferentAnnotation
@DifferentAnnotation(name = "My Class") public class MyClass { @MyAnnotation private String field; // ... }
此代码将打印My Class:
My Class
String diffAnnotationName = findAnnotationValue(fieldTypeElement, "com.example.DifferentAnnotation", "name", String.class); System.out.println(diffAnnotationName);