How to get annotation class name, attribute values using reflection
Solution 1
Contrary to what one might expect, the elements of an annotation are not attributes - they are actually methods that return the provided value or a default value.
You have to iterate through the annotations' methods and invoke them to get the values. Use annotationType()
to get the annotation's class, the object returned by getClass()
is just a proxy.
Here is an example which prints all elements and their values of the @Resource
annotation of a class:
@Resource(name = "foo", description = "bar")
public class Test {
public static void main(String[] args) throws Exception {
for (Annotation annotation : Test.class.getAnnotations()) {
Class<? extends Annotation> type = annotation.annotationType();
System.out.println("Values of " + type.getName());
for (Method method : type.getDeclaredMethods()) {
Object value = method.invoke(annotation, (Object[])null);
System.out.println(" " + method.getName() + ": " + value);
}
}
}
}
Output:
Values of javax.annotation.Resource
name: foo
type: class java.lang.Object
lookup:
description: bar
authenticationType: CONTAINER
mappedName:
shareable: true
Thanks to Aaron for pointing out the you need to cast the null
argument to avoid warnings.
Solution 2
Just to follow up on the answer above (I don't have enough rep to reply to it):
method.invoke(annotation, null)
should be changed to the following, otherwise it throws an exception:
method.invoke(annotation, (Object[])null) or method.invoke(annotation, new Object[0])
Jianwu Chen
Updated on July 09, 2022Comments
-
Jianwu Chen almost 2 years
I know if we know the annotation class, we can easily get the specific annotation and access its attribute. For example:
field.getAnnotation(Class<T> annotationClass)
Which will return a reference of specific annotation interface, so you can easily access its values.
My question is if I have no pre knowledge about the particular annotations class. I just want to use reflection to get all the annotation class name and their attributes at run-time for the purpose of dumping the class information for example as a JSON file. How can I do it in an easy way.
Annotation[] field.getAnnotations();
This method will only return dynamic proxies of the annotation interfaces.
-
kapex almost 9 yearsThanks, I've updated my answer with your improvement! I think it only creates a compiler warning and not an exception, but you are right that it should be changed as you suggest.
-
AouledIssa about 4 yearsis it possible to use reflection at compile-time?
-
kapex about 4 years@MohamedAouledIssa Do you mean something like reading the value of an annotation during compilation and e.g. validate it? That can't be done with regular Java reflection. But it can be done with an Annotation Processor which is run during compilation. The relevant Java APIs for this are javax.annotation.processing and javax.lang.model, which could be described as compile-time reflections
-
AouledIssa about 4 yearsRight! I Have written a dozen of annotation processors in my career so it's something obvious and that's what it was designed for actually. My use case is pretty much specific. I have an android app that has multiple modules and i want to be able to write some code in a specific module, something not possible with annotation processors even when i specifically define the output dir. Any ideas how to solve this? Many thanks
-
kapex about 4 years@MohamedAouledIssa Generating additional code during compilation is generally supported by annotation processors. At least for regular Java - I don't know if Android annotation processing may have some limitations here. Annotation processors are not allowed to modify code, but if you need that it apparently can still be done: stackoverflow.com/q/13690272/897024 (again at least in Java, by modifying byte code. Android may works differently here but since there is Lombok for Android, I guess it is possible)
-
AouledIssa about 4 yearsAndroid AP is the same as Java AP. nothing fancy to be honest but the problem is that i can't have my Annotation processor generate classes at a different location from the default one. I can do that if the output dir is in the same submodule but never in a different module. Annotation processor in module A will not be able to generate code in submodule B. I don't need to modify the code. I just need to output it somewhere else.
-
AouledIssa about 4 yearsHold on!! I figured out that I was doing it wrongly. I need to pass the absolute path instead of the relative path!