java source code analysis - annotation AnnotatedElement interface

java source code analysis - annotation AnnotatedElement interface

summary

When we explained the annotated runtime processor, we wrote this Code:

 //Get getPersonInfo Method through Class object
Method method = clazz.getDeclaredMethod("getPersonInfo", null);
System.out.println(method.getName());
//Get the annotation on the Method according to the Method
MyPersonAnnotation declaredAnnotations = method.getDeclaredAnnotation(MyPersonAnnotation.class);
System.out.println(declaredAnnotations);

The annotation information on the Method is obtained by calling getAnnotation(MyPersonAnnotation.class) of the Method object, which is typically obtained through reflection. One question, how do annotations and reflections relate?

In fact, we should understand the principle first. The key point is in the AnnotatedElement interface. The AnnotatedElement interface represents an element that can be annotated in the currently running virtual machine. It provides some abstract methods to read the annotation information on the annotated element through reflection.

Let's take a look at the class diagram of this interface:

We know from the above figure:

Sub interface

  • AnnotatedType: annotated type;
  • AnnotatedTypeVariable: annotated type variable;
  • AnnotatedArrayType: annotated array type;
  • Annotatedparameterizedtype: annotated parameterized type;
  • Annotatedwidcardtype: annotated generic type;
  • GenericDeclaration: general declaration, used to represent declared type elements, such as classes, methods, constructors, etc;

Implementation class

  • AccessibleObject: accessible objects, such as methods, constructors, properties, etc;
  • Class: class;
  • Constructor: constructor;
  • Executable: executable, such as constructors and methods;
  • Field: field attribute;
  • Method: method;
  • Package: package;
  • Parameter: parameter;

method

The source code of AnnotatedElement is as follows:

public interface AnnotatedElement {
    
    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return getAnnotation(annotationClass) != null;
    }

   
    <T extends Annotation> T getAnnotation(Class<T> annotationClass);

    
    Annotation[] getAnnotations();

   
    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
         /*
          * Definition of associated: directly or indirectly present OR
          * neither directly nor indirectly present AND the element is
          * a Class, the annotation type is inheritable, and the
          * annotation type is associated with the superclass of the
          * element.
          */
         T[] result = getDeclaredAnnotationsByType(annotationClass);

         if (result.length == 0 && // Neither directly nor indirectly present
             this instanceof Class && // the element is a class
             AnnotationType.getInstance(annotationClass).isInherited()) { // Inheritable
             Class<?> superClass = ((Class<?>) this).getSuperclass();
             if (superClass != null) {
                 // Determine if the annotation is associated with the
                 // superclass
                 result = superClass.getAnnotationsByType(annotationClass);
             }
         }

         return result;
     }

    
    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
         Objects.requireNonNull(annotationClass);
         // Loop over all directly-present annotations looking for a matching one
         for (Annotation annotation : getDeclaredAnnotations()) {
             if (annotationClass.equals(annotation.annotationType())) {
                 // More robust to do a dynamic cast at runtime instead
                 // of compile-time only.
                 return annotationClass.cast(annotation);
             }
         }
         return null;
     }

    
    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return AnnotationSupport.
            getDirectlyAndIndirectlyPresent(Arrays.stream(getDeclaredAnnotations()).
                                            collect(Collectors.toMap(Annotation::annotationType,
                                                                     Function.identity(),
                                                                     ((first,second) -> first),
                                                                     LinkedHashMap::new)),
                                            annotationClass);
    }

    
    Annotation[] getDeclaredAnnotations();
}

(1) isAnnotationPresent method

default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return getAnnotation(annotationClass) != null;
    }

If the annotation of the specified type appears on the current element, it will be put back to true, otherwise it will return false; Note the defalut keyword, so that the methods in the interface can have some default implementations.

(2) getAnnotation method:

<T extends Annotation> T getAnnotation(Class<T> annotationClass);

If there is an annotation of the type specified by the parameter (annotationClass) on the current element, the corresponding annotation will be returned; otherwise, null will be returned.

(3) getAnnotations method

Annotation[] getAnnotations();

Used to get all annotations on this element and put them back in array form. If there is no annotation on the element, an array of length 0 is returned.

The array obtained by calling this method can be modified freely and will not affect the array returned to other callers.

(4) getAnnotationsByType method

default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
         
         T[] result = getDeclaredAnnotationsByType(annotationClass);

         if (result.length == 0 && // Neither directly nor indirectly present
             this instanceof Class && // the element is a class
             AnnotationType.getInstance(annotationClass).isInherited()) { // Inheritable
             Class<?> superClass = ((Class<?>) this).getSuperclass();
             if (superClass != null) {
                 // Determine if the annotation is associated with the
                 // superclass
                 result = superClass.getAnnotationsByType(annotationClass);
             }
         }

         return result;
     }

Gets the annotation associated with the element. If there is no annotation associated with this element, the return value is an array of length 0. The difference between this method and getAnnotation(Class) is that it detects whether its parameter is a repeatable annotation type (that is, whether it is @ Repeatable). If so, it tries to find one or more annotations of this type through the "looking through" container annotation.

(5) Getdeclaraedannotation method

default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
         Objects.requireNonNull(annotationClass);
         // Loop over all directly-present annotations looking for a matching one
         for (Annotation annotation : getDeclaredAnnotations()) {
             if (annotationClass.equals(annotation.annotationType())) {
                 // More robust to do a dynamic cast at runtime instead
                 // of compile-time only.
                 return annotationClass.cast(annotation);
             }
         }
         return null;
     }

Get the annotation that appears directly on this element. This method ignores inherited annotations. If there is no immediate annotation on this element, the return value is an array of length 0.

Keywords: source code

Added by gijs25 on Sun, 10 Oct 2021 04:21:07 +0300