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 hav
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.
Rather crude way using the proxy approach with the help of Apache Commons AnnotationUtils
public static <A extends Annotation> A mockAnnotation(Class<A> annotationClass, Map<String, Object> properties) {
return (A) Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class<?>[] { annotationClass }, (proxy, method, args) -> {
Annotation annotation = (Annotation) proxy;
String methodName = method.getName();
switch (methodName) {
case "toString":
return AnnotationUtils.toString(annotation);
case "hashCode":
return AnnotationUtils.hashCode(annotation);
case "equals":
return AnnotationUtils.equals(annotation, (Annotation) args[0]);
case "annotationType":
return annotationClass;
default:
if (!properties.containsKey(methodName)) {
throw new NoSuchMethodException(String.format("Missing value for mocked annotation property '%s'. Pass the correct value in the 'properties' parameter", methodName));
}
return properties.get(methodName);
}
});
}
The types of passed properties are not checked with the actual type declared on the annotation interface and any missing values are discovered only during runtime.
Pretty similar in function to the code mentioned in kaqqao's answer (and probably Gunnar's Answer as well), without the downsides of using internal Java API as in Tobias Liefke's answer.