Difference between Field#getAnnotations() and Field#getDeclaredAnnotations()

10,711

Solution 1

Looking in the source-code gives the answer:

excerpt from java.lang.reflect.AccessibleObject:

/**
 * @since 1.5
 */
public Annotation[] getAnnotations() { 
    return getDeclaredAnnotations();
}

/**
 * @since 1.5
 */
public Annotation[] getDeclaredAnnotations()  {
    throw new AssertionError("All subclasses should override this method");
}

And since Field does not override getAnnotations(): getDeclaredAnnotations() is called.

So both methods do the same when called on a java.lang.reflect.Field object. (so the JavaDoc is wrong in my opinion)

the other case is java.lang.Class which overrides both methods (and does what it's JavaDoc says ;) ):

/**
 * @since 1.5
 */
public Annotation[] getAnnotations() { 
    initAnnotationsIfNecessary();
    return AnnotationParser.toArray(annotations);
}

/**
 * @since 1.5
 */
public Annotation[] getDeclaredAnnotations()  {
    initAnnotationsIfNecessary();
    return AnnotationParser.toArray(declaredAnnotations);
}

Solution 2

getDeclaredAnnotations() provides direct implemented annotations only where as getAnnotations() provide direct implemented as well as inheritable annotations(@Inherited) from its parent class.

Solution 3

It's the opposite. getDeclaredAnnotations() - as the docs says - is the only method that ignores inherited annotations.

Below is snippet that demostrates the difference:

public class Test1 {
    public static void main(String[] args) {
        Test3 test = new Test3();

        for (Annotation annotation : test.getClass().getAnnotations()) {
            System.out.println("Class getAnnotations: " + annotation);
        }

        for (Annotation annotation : test.getClass().getDeclaredAnnotations()) {
            System.out.println("Class getDeclaredAnnotations: " + annotation);
        }

        for (Field field : test.getClass().getFields()) {
            for (Annotation annotation : field.getAnnotations()) {
                System.out.println("Field getAnnotations: " + annotation);
        }

        for (Annotation annotation : field.getDeclaredAnnotations()) {
            System.out.println("Field getDeclaredAnnotations: " + annotation);
        }
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface CustomAnnotation {
    String value();
}

@CustomAnnotation("Class")
class Test2 {
    @CustomAnnotation("Field") public String testString;
}

 class Test3 extends Test2 {} 

The output will be `getAnnotations:

Class getAnnotations: @test.CustomAnnotation(value=Class)
Field getAnnotations: @test.CustomAnnotation(value=Field)
Field getDeclaredAnnotations: @test.CustomAnnotation(value=Field)

You see that the Class getDeclaredAnnotations() is empty, because class Test3 does not have annotations itself, only inherited ones from Test2.

From the Javadoc for @Inherited:

Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached. If no superclass has an annotation for this type, then the query will indicate that the class in question has no such annotation. Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.

Share:
10,711
Philipp Sander
Author by

Philipp Sander

I'm a softwaredeveloper (mostly backend), gamer, fitness enthusiast and hobby-hopper. Magento2 Certification Profile | Scrum Certification Profile

Updated on June 21, 2022

Comments

  • Philipp Sander
    Philipp Sander about 2 years

    JavaDoc says the following:

    AccessibleObject#getDeclaredAnnotations:

    Returns all annotations that are directly present on this element. Unlike the other methods in this interface, this method ignores inherited annotations. (Returns an array of length zero if no annotations are directly present on this element.) The caller of this method is free to modify the returned array; it will have no effect on the arrays returned to other callers.

    Field#getAnnotations:

    Returns all annotations present on this element. (Returns an array of length zero if this element has no annotations.) The caller of this method is free to modify the returned array; it will have no effect on the arrays returned to other callers.

    Since getAnnotations is inherited from class java.lang.reflect.AccessibleObject, have Field objects access to it.

    As i understand it is the only difference between them that getDeclaredAnnotations ignores inherited annotations. I get that when dealing with Classes but as far as i know Fields can NOT inherit annotations.

  • Sotirios Delimanolis
    Sotirios Delimanolis almost 11 years
    How does this apply to Field? Also OP states I get that when dealing with Classes
  • Philipp Sander
    Philipp Sander almost 11 years
    i know how it works with Class but i don't get field. but thanks for pointing out that i got the ignoring wrong
  • Philipp Sander
    Philipp Sander almost 11 years
    thanks for updating your snippet, buti still see no difference between the too methods...