【问题标题】:Java annotation - how to get properties and class in processorJava注解-如何在处理器中获取属性和类
【发布时间】:2012-05-18 22:12:12
【问题描述】:

对于下面的自定义Java注解

@CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode
{ 
   ... 
}

我基本上希望能够在编译时同时获取 MyApplicationCode 的 Class 对象和 clazz 参数,以确认一些编码约定的一致性(另一个故事)。 基本上,我希望能够访问注释处理器中的 MyApplicationCode.class 和 Someclass.class 代码。我快到了,但我错过了一些东西。我有

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface CustomAnnotation
{
   public Class clazz();
}

然后我有处理器:

public class CustomAnnotationProcessor extends AbstractProcessor
{
    private ProcessingEnvironment processingEnvironment;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment)
    {
        this.processingEnvironment = processingEnvironment;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)    
    {
        Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);

        for(Element e : elements)
        {
            Annotation annotation = e.getAnnotation(CustomAnnotation.class);
            Class clazz = ((CustomAnnotation)annotation).clazz();        

            // How do I get the actual CustomAnnotation clazz?
            // When I try to do clazz.getName() I get the following ERROR:
            // Attempt to access Class object for TypeMirror SomeClass

            // Also, how do I get the Class object for the class that has the annotation within it?
            // In other words, how do I get MyApplicationCode.class?
        }
    }
}

所以我在 process 方法中尝试做的是从下面的原始代码中获取 SomeClass.class 和 MyApplication.class 以在编译时进行一些自定义验证。我似乎一生都无法弄清楚如何获得这两个值......

@CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode

更新:以下帖子有更多细节,而且更接近。但问题是你最终还是会得到一个 TypeMirror 对象来从中提取类对象,它没有解释:http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/

Update2:你可以通过做得到MyApplication.class

String classname = ((TypeElement)e).getQualifiedName().toString();

【问题讨论】:

标签: java annotations


【解决方案1】:

我正打算将您指向博客 http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/ 的方向,但看起来您已经找到了。

我看到你知道如何访问 MyApplication 元素,所以我不会介绍它......

您看到的异常实际上包含其中的注释属性的类型。所以你可以在捕获异常时引用注解clazz值:

public class CustomAnnotationProcessor extends AbstractProcessor
{
    private ProcessingEnvironment processingEnvironment;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment)
    {
        this.processingEnvironment = processingEnvironment;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)    
    {
        Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);

        for(Element e : elements)
        {
            CustomAnnotation annotation = e.getAnnotation(CustomAnnotation.class);    

            TypeMirror clazzType = null;
            try {
                annotation.clazz();
            } catch (MirroredTypeException mte) {
                clazzType = mte.getTypeMirror();
            }

            System.out.println(clazzType); // should print out SomeClass

        }
    }
}

是的,这是一个完全破解的解决方案,我不确定 API 开发人员为什么决定使用注释处理器功能朝这个方向发展。但是,我看到很多人实现了这个(包括myself),并且提到的文章也描述了这种技术。目前这似乎是一个可以接受的解决方案。

就“获取”MyApplicationCode 和 SomeClass 的类值而言,如果它们是正在编译的类,您将无法这样做。但是,您可以使用 Element 和 TypeMirror 表示对您的类(方法、字段、类名称、存在的注释等)执行一些高级验证

【讨论】:

    【解决方案2】:

    读完这个related SO question后,我发现了这个excellent page about the Java Annotation Processing Tool (APT)。它是从 2005 年开始的,所以现在可能不是最好的方法。

    APT [...] 是 Java 的注解处理工具。更具体地说,APT 允许您插入代码以在代码编译发生时处理源文件中的注释 - 在此过程中,您可以发出注释、警告和错误。

    这仅适用于 Oracle 的 JDK。

    【讨论】:

    • 这是我主要参考的 4 个网站之一。问题是我找不到任何有信息的人。问题实际上在于试图通过一个类。如果您使用字符串等,这真的很简单,但是当您尝试放置一个类时,它会变得非常复杂。这就是我第一次更新中的链接所讨论的内容。
    【解决方案3】:

    现在是编译时间。我认为编译器甚至还没有完成源代码的编译。您从 AnnotatedElement 实例中检索此类信息,该实例将为您提供已注释类型的相关信息,但不提供其运行时属性,因为相关类文件尚未由虚拟机加载,因此尚不可用。并且编译器甚至不能保证在 ja​​va 的虚拟机下运行,因此不强制要求能够加载类文件。它的要求只是能够生成任何特定虚拟机都可以读取的字节码。

    因此,请检查镜像 Api,有关您已注释的类/方法/字段的任何相关信息,请检查表示该实例的 AnnotatedElement。

    顺便说一句:这只是我推断出来的信息,所以它可能不是真正的事实。

    【讨论】:

    • 您认为 Suppress、Override 等注解如何工作?他们必须能够读取类对象;)
    • 您是否曾尝试在运行时获取 Override 注解的实例?你不能,因为它没有编译到类文件中。它甚至在编译完成之前就被丢弃了。它的语义只检查是否存在超类方法定义,与源是否已编译无关。源文件注释用 AnnotatedElement 表示,以便为您提供有关带注释类型的信息,而不是它们的运行时属性,而不是在编译时。您可以查看 AnnotatedElement 源文件吗?
    猜你喜欢
    • 2023-03-04
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多