42

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.

3
  • 1
    What's wrong with field.getAnnotations()? You can easily determine the annotation class by calling 'annotationType()' on each Annotation object.
    – isnot2bad
    Commented Dec 3, 2013 at 21:59
  • Thanks. It works. The annotation interface is not following java bean naming convention, so when I try getXXX, I didn't find this method. For the attributes. it's also not following java bean naming convention, I have to use special logic to find the attributes reflectively. I have implemented it using reflection. Commented Dec 3, 2013 at 22:23
  • Its an old post but still if you want to access value of your annotation's attribute you can use the following code: Field[] fields = Test.class.getDeclaredFields(); for (Field field : fields) { if(field.isAnnotationPresent(FieldDescr.class)){ MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class); System.out.println(myAnnoatation.name()); } } In the above example name is the attribute of MyAnnotion which is an annotation interface.
    – Terry
    Commented Mar 23, 2016 at 11:08

2 Answers 2

86

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.

6
  • is it possible to use reflection at compile-time?
    – AouledIssa
    Commented Apr 16, 2020 at 11:17
  • 1
    @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
    – kapex
    Commented Apr 17, 2020 at 10:28
  • 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
    – AouledIssa
    Commented Apr 17, 2020 at 10:57
  • @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)
    – kapex
    Commented Apr 17, 2020 at 11:19
  • 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
    Commented Apr 17, 2020 at 11:23
15

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])
1
  • 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.
    – kapex
    Commented Jun 3, 2015 at 17:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.