How to get annotation class name, attribute values using reflection

80,433

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])
Share:
80,433
Jianwu Chen
Author by

Jianwu Chen

Updated on July 09, 2022

Comments

  • Jianwu Chen
    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
    kapex almost 9 years
    Thanks, 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
    AouledIssa about 4 years
    is it possible to use reflection at compile-time?
  • kapex
    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
    AouledIssa about 4 years
    Right! 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
    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
    AouledIssa about 4 years
    Android 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
    AouledIssa about 4 years
    Hold on!! I figured out that I was doing it wrongly. I need to pass the absolute path instead of the relative path!