How to create an instance of an annotation
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.
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?
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:
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.
The proxy approach, as suggested in Gunnar's answer is already implemented in 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.
The library itself is tiny and has no dependencies (and does not rely on JDK internal APIs).
Disclosure: I'm the developer behind GeantyRef.