如何创建注释的实例

car*_*ing 52 java reflection annotations

我正在尝试做一些Java注释魔术.我必须说我仍在追赶注释技巧,而且某些事情对我来说仍然不太清楚.

所以...我有一些带注释的类,方法和字段.我有一个方法,它使用反射对类运行一些检查并将一些值注入到类中.一切正常.

但是,我现在面临的情况是我需要一个注释的实例(可以这么说).所以...注释不像常规接口,你不能做一个类的匿名实现.我知道了.我在这里看了一些关于类似问题的帖子,但我似乎无法找到我正在寻找的答案.

我基本上想得到一个注释的实例,并能够使用反射设置它的一些字段(我想).有没有办法做到这一点?

car*_*ing 64

好吧,显然没有什么比这更复杂了.真!

正如同事所指出的,你可以简单地创建一个匿名的注释实例(就像任何接口一样):

MyAnnotation:

public @interface MyAnnotation
{

    String foo();

}
Run Code Online (Sandbox Code Playgroud)

调用代码:

class MyApp
{
    MyAnnotation getInstanceOfAnnotation(final String foo)
    {
        MyAnnotation annotation = new MyAnnotation()
        {
            @Override
            public String foo()
            {
                return foo;
            }

            @Override
            public Class<? extends Annotation> annotationType()
            {
                return MyAnnotation.class;
            }
        };

        return annotation;
    }
}
Run Code Online (Sandbox Code Playgroud)

Martin Grigorov的学分.

  • 根据`Annotation`的JavaDoc,你需要实现`equals`和`hashCode`.例如,`java.inject.Inject`的限定符注释可能会遇到问题,无法找到正确的bean. (5认同)
  • 警告:"MyAnnotation"的匿名实例是类的实例,而不是注释,即`annotation.getClass().isInterface()`和`annotation.getClass().isAnnotation()`返回`false`. (4认同)
  • 另一个警告:`annotation.getClass()`也没有'MyAnnotation`的潜在元注释.要访问它们,首先必须得到原始类:`annotation.getClass().getInterfaces()[0]`.当我需要在测试中模拟注释时,我遇到了这个问题.(注意`@ Inherited`没有帮助,因为它是关于继承具有注释的类,而不是注释本身.) (4认同)

kaq*_*qao 11

Gunnar的答案中建议的代理方法已在GeAnTyRef中实现:

Map<String, Object> annotationParameters = new HashMap<>();
annotationParameters.put("name", "someName");
MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters);
Run Code Online (Sandbox Code Playgroud)

这将产生一个等同于你得到的注释:

@MyAnnotation(name = "someName")
Run Code Online (Sandbox Code Playgroud)

这种方式生产的注释情况下将采取行动等同于在Java正常生产的那些,他们hashCodeequals已经正确实施的兼容性,所以没有离奇的注意事项就像在实例化注释作为公认的答案.事实上,JDK内部使用相同的方法:sun.reflect.annotation.AnnotationParser#annotationForMap.

库本身很小,没有依赖性.

披露:我是GeAnTyRef背后的开发人员.


Rav*_*wal 11

您还可以绝对愚蠢地(但简单地)创建一个虚拟注释目标并从那里获取它

@MyAnnotation(foo="bar", baz=Blah.class)
private static class Dummy {}
Run Code Online (Sandbox Code Playgroud)

final MyAnnotation annotation = Dummy.class.getAnnotation(MyAnnotation.class)
Run Code Online (Sandbox Code Playgroud)

创建方法/参数目标注释实例可能会更复杂一些,但这种方法的优点是可以像 JVM 通常那样获取注释实例。不用说,它是尽可能简单的。


Gun*_*nar 6

你可以使用一个注释代理,如这一个,或这一个从Hibernate验证项目(免责声明:我是后者的提交者).

  • 这些链接现在已断开,您是否有可能内嵌应该存在的代码? (2认同)

Tob*_*fke 6

你可以使用sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map):

public @interface MyAnnotation {
    String foo();
}

public class MyApp {
    public MyAnnotation getInstanceOfAnnotation(final String foo) {
        MyAnnotation annotation = AnnotationParser.annotationForMap(
            MyAnnotation.class, Collections.singletonMap("foo", "myFooResult"));
    }
}
Run Code Online (Sandbox Code Playgroud)

缺点:来自sun.*更高版本的类可能会发生更改(尽管此方法自Java 5以来具有相同的签名)并且不适用于所有Java实现,请参阅此讨论.

如果这是一个问题:您可以使用自己的代理创建一个通用代理InvocationHandler- 这正是AnnotationParser内部正在为您做的事情.或者您使用自己在此MyAnnotation定义的实现.在这两种情况下,您都应该记住实施,并且结果是专门记录的.annotationType()equals()hashCode()java.lang.Annotation