首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在批注处理器中获取字段类

在批注处理器中获取字段类
EN

Stack Overflow用户
提问于 2013-07-16 01:43:31
回答 1查看 12.7K关注 0票数 19

我正在编写我的第一个注解处理器,在一些看似微不足道的事情上遇到了麻烦,但我找不到任何有关它的信息。

我用我的注解注释了一个元素

代码语言:javascript
复制
@MyAnnotation String property;

当我在处理器中将此属性作为元素获取时,似乎无法以任何方式获取元素的类型。在这种情况下,需要获取表示字符串的类或TypeElement实例。

我尝试用Class.forName()实例化容器类型的类对象,但它抛出了一个ClassNotFoundException。我想这是因为我不能访问包含类的类加载器?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-16 02:08:10

在运行批注处理器时,您不能访问已编译的类。批注处理的要点是它是预编译的。

相反,您需要创建一个专门处理您的注释类型的注释处理器,然后使用镜像API访问该字段。例如:

代码语言:javascript
复制
@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这样的东西来使用任何尚未编译的类(包括那些即将使用注释编译的类)。对于这些,您必须仅使用的字符串。这是因为批注处理发生在称为“源代码生成”的预编译阶段,这允许您在编译器使用批注运行之前生成源代码。

验证字段类型是否为java.lang.String (已编译)的示例验证:

代码语言:javascript
复制
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);
    }
}

资源

编辑:

我想要获取字段类型,以获得该类型的注释。但这似乎不太可能?

这确实是可能的!这可以在TypeMirror上使用更多的方法来完成

代码语言:javascript
复制
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();

从这里开始,您有两个选择:

  1. 如果您试图查找的批注已经编译(即,它来自另一个库),那么您可以直接引用类来获取annotation.
  2. If您试图查找的批注没有编译(即,它是在运行APT的javac的当前调用中编译的),那么您可以通过AnnotationMirror实例引用它。

已编译

代码语言:javascript
复制
DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation(
        DifferentAnnotation.class);
// Process diffAnn

非常简单,这使您可以直接访问注释本身。

未编译

请注意,无论注释是否被编译,这个解决方案都可以工作,只是它不像上面的代码那样干净。

下面是我曾经写过的几个方法,它们通过类名称从注释镜像中提取特定的值:

代码语言:javascript
复制
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注释,源代码如下所示:

代码语言:javascript
复制
@DifferentAnnotation(name = "My Class")
public class MyClass {

    @MyAnnotation
    private String field;

    // ...
}

此代码将打印My Class

代码语言:javascript
复制
String diffAnnotationName = findAnnotationValue(fieldTypeElement,
        "com.example.DifferentAnnotation", "name", String.class);
System.out.println(diffAnnotationName);
票数 56
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17660469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档