I am trying to do some Java annotation magic. I must say I am still catching up on annotation tricks and that certain things are still not quite clear to me.
我正在尝试做一些Java注释魔术。我必须说我仍在追赶注释技巧,而且某些事情对我来说仍然不太清楚。
So... I have some annotated classes, methods and fields. I have a method, which uses reflection to run some checks on the classes and inject some values into a class. This all works fine.
所以...我有一些带注释的类,方法和字段。我有一个方法,它使用反射对类运行一些检查并将一些值注入到类中。一切正常。
However, I am now facing a case where I need an instance (so to say) of an annotation. So... annotations aren't like regular interfaces and you can't do an anonymous implementation of a class. I get it. I have looked around some posts here regarding similar problems, but I can't seem to be able to find the answer to what I am looking for.
但是,我现在面临的情况是我需要一个注释的实例(可以这么说)。所以...注释不像常规接口,你不能做一个类的匿名实现。我知道了。我在这里看了一些关于类似问题的帖子,但我似乎无法找到我正在寻找的答案。
I would basically like to get and instance of an annotation and be able to set some of it's fields using reflection (I suppose). Is there at all a way to do this?
我基本上想得到一个注释的实例,并能够使用反射设置它的一些字段(我想)。有没有办法做到这一点?
4 个解决方案
#1
55
Well, it's apparently nothing all that complicated. Really!
嗯,显然没有什么复杂的。真!
As pointed out by a colleague, you can simply create an anonymous instance of the annotation (like any interface) like this:
正如同事所指出的,你可以简单地创建一个匿名的注释实例(就像任何接口一样):
MyAnnotation:
MyAnnotation:
public @interface MyAnnotation
{
String foo();
}
Invoking code:
调用代码:
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;
}
}
Credits to Martin Grigorov.
致Martin Grigorov的学分。
#2
8
The proxy approach, as suggested in Gunnar's answer is already implemented in GeAnTyRef:
Gunnar的答案中建议的代理方法已在GeAnTyRef中实现:
Map<String, Object> annotationParameters = new HashMap<>();
annotationParameters.put("name", "someName");
MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters);
This will produce an annotation equivalent to what you'd get from:
这将产生一个等同于你得到的注释:
@MyAnnotation(name = "someName")
Annotation instances produced this way will act identical to the ones produced by Java normally, and their hashCode
and equals
have been implemented properly for compatibility, so no bizarre caveats like with directly instantiating the annotation as in the accepted answer. In fact, JDK internally uses this same approach: sun.reflect.annotation.AnnotationParser#annotationForMap.
以这种方式生成的注释实例将通常与Java生成的注释实例相同,并且它们的hashCode和equals已经正确实现以实现兼容性,因此没有像在接受的答案中直接实例化注释那样奇怪的警告。事实上,JDK内部使用相同的方法:sun.reflect.annotation.AnnotationParser#annotationForMap。
The library itself is tiny and has no dependencies.
库本身很小,没有依赖性。
Disclosure: I'm the developer behind GeAnTyRef.
披露:我是GeAnTyRef背后的开发人员。
#3
#4
5
You can use sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map)
:
您可以使用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"));
}
}
Downside: Classes from sun.*
are subject to change in later versions (allthough this method exists since Java 5 with the same signature) and are not available for all Java implementations, see this discussion.
缺点:来自sun。*的类可能会在更高版本中发生变化(尽管此方法自Java 5以来具有相同的签名)并且不适用于所有Java实现,请参阅此讨论。
If that is a problem: you could create a generic proxy with your own InvocationHandler
- this is exactly what AnnotationParser
is doing for you internally. Or you use your own implementation of MyAnnotation
as defined here. In both cases you should remember to implement annotationType()
, equals()
and hashCode()
as the result is documented specifically for java.lang.Annotation
.
如果这是一个问题:您可以使用自己的InvocationHandler创建一个通用代理 - 这正是AnnotationParser在内部为您做的事情。或者您使用自己的MyAnnotation实现,如此处所定义。在这两种情况下,您都应该记住实现annotationType(),equals()和hashCode(),因为结果是专门为java.lang.Annotation记录的。
#1
55
Well, it's apparently nothing all that complicated. Really!
嗯,显然没有什么复杂的。真!
As pointed out by a colleague, you can simply create an anonymous instance of the annotation (like any interface) like this:
正如同事所指出的,你可以简单地创建一个匿名的注释实例(就像任何接口一样):
MyAnnotation:
MyAnnotation:
public @interface MyAnnotation
{
String foo();
}
Invoking code:
调用代码:
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;
}
}
Credits to Martin Grigorov.
致Martin Grigorov的学分。
#2
8
The proxy approach, as suggested in Gunnar's answer is already implemented in GeAnTyRef:
Gunnar的答案中建议的代理方法已在GeAnTyRef中实现:
Map<String, Object> annotationParameters = new HashMap<>();
annotationParameters.put("name", "someName");
MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters);
This will produce an annotation equivalent to what you'd get from:
这将产生一个等同于你得到的注释:
@MyAnnotation(name = "someName")
Annotation instances produced this way will act identical to the ones produced by Java normally, and their hashCode
and equals
have been implemented properly for compatibility, so no bizarre caveats like with directly instantiating the annotation as in the accepted answer. In fact, JDK internally uses this same approach: sun.reflect.annotation.AnnotationParser#annotationForMap.
以这种方式生成的注释实例将通常与Java生成的注释实例相同,并且它们的hashCode和equals已经正确实现以实现兼容性,因此没有像在接受的答案中直接实例化注释那样奇怪的警告。事实上,JDK内部使用相同的方法:sun.reflect.annotation.AnnotationParser#annotationForMap。
The library itself is tiny and has no dependencies.
库本身很小,没有依赖性。
Disclosure: I'm the developer behind GeAnTyRef.
披露:我是GeAnTyRef背后的开发人员。
#3
7
You could use an annotation proxy such as this one, or this one from the Hibernate Validator project (disclaimer: I'm a committer of the latter).
您可以使用这样的注释代理,或者来自Hibernate Validator项目的注释代理(免责声明:我是后者的提交者)。
#4
5
You can use sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map)
:
您可以使用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"));
}
}
Downside: Classes from sun.*
are subject to change in later versions (allthough this method exists since Java 5 with the same signature) and are not available for all Java implementations, see this discussion.
缺点:来自sun。*的类可能会在更高版本中发生变化(尽管此方法自Java 5以来具有相同的签名)并且不适用于所有Java实现,请参阅此讨论。
If that is a problem: you could create a generic proxy with your own InvocationHandler
- this is exactly what AnnotationParser
is doing for you internally. Or you use your own implementation of MyAnnotation
as defined here. In both cases you should remember to implement annotationType()
, equals()
and hashCode()
as the result is documented specifically for java.lang.Annotation
.
如果这是一个问题:您可以使用自己的InvocationHandler创建一个通用代理 - 这正是AnnotationParser在内部为您做的事情。或者您使用自己的MyAnnotation实现,如此处所定义。在这两种情况下,您都应该记住实现annotationType(),equals()和hashCode(),因为结果是专门为java.lang.Annotation记录的。