[custom annotation, objects can all understand]

Posted by dr.wong on Tue, 28 Dec 2021 11:53:02 +0100

Girlfriend: I want my own annotation, you teach me!

moon: eh? Why do you suddenly want your own annotation?

Girlfriend: none of your business! "Break up"!

moon: No, no, no, no! I teach you!

moon: look at my treasure. You're good at spring. Let me show you Autowired first

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
 /**
  * Declares whether the annotated dependency is required.
  * <p>Defaults to {@code true}.
  */
 boolean required() default true;
}

moon: when you see "Autowired", you find that the "class name" of this class is called Autowired, so do you know why @ Autowired is posted?

Girlfriend: Oh Oh Oh! I see! The original "class name is the annotation name"!

moon: my girlfriend is smart! Let's take a look again. There is another special thing about it. The class flag is class, and the annotation flag is @ interface.

Girlfriend: Um Good, good, you go on

moon: let's take another look at @ Autowired. There are three annotations on @ Autowired. What are their functions? Let's first look at the first "@ Documented"

/**
 * Indicates that annotations with a type are to be documented by javadoc
 * and similar tools by default.  This type should be used to annotate the
 * declarations of types whose annotations affect the use of annotated
 * elements by their clients.  If a type declaration is annotated with
 * Documented, its annotations become part of the public API
 * of the annotated elements.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

moon: look, we found that the first one is @ Documented. Let's see what its comments are?

moon: through my strong English reading ability, I found that "@ Documented annotation is actually only used to generate documents". api documents can be generated by using javadoc, so this annotation must be "unimportant"

Girlfriend: bah! You obviously rely on translation! study slacker!

moon: Hey, hey, let's see the next one! 「@Retention」! That's enough

/**
 * Indicates how long annotations with the annotated type are to
 * be retained.  If no Retention annotation is present on
 * an annotation type declaration, the retention policy defaults to
 * {@code RetentionPolicy.CLASS}.
 *
 * <p>A Retention meta-annotation has effect only if the
 * meta-annotated type is used directly for annotation.  It has no
 * effect if the meta-annotated type is used as a member type in
 * another annotation type.
 *
 * @author  Joshua Bloch
 * @since 1.5
 * @jls 9.6.3.2 @Retention
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

moon: again, through my strong English reading ability, what does this annotation mean?

moon: in fact, it tells you how long the "life cycle" of the annotation is, and the definition of this life cycle is "in the RetentionPolicy". Let's see what the RetentionPolicy is?

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

Girlfriend: I know this well! "SOURCE means to be applied to the SOURCE code, CLASS means to be applied to the compiled SOURCE code, and RUNTIME means to be applied only to the RUNTIME"! These are the three states of Java!

moon: you have learned to answer my treasure!!!!

Girlfriend: hum! Go on!!

moon: hahaha, OK, let's talk about the last Annotation "@ Target"

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

moon: the function of this annotation is actually very simple, "that is to tell you which scopes the annotation can be pasted in", and what scopes do you know?

Girlfriend: Well There are classes, methods, member variables

moon: hahaha, I don't know!!

Girlfriend: hum!! "Break up"!!!!

moon: No, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no! This scope is actually hidden in the "ElementType []" array. Let's go in and have a look!

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

moon: there are "10 Scopes" in total

Scopemeaning
TYPEUsed to describe a class, interface (including annotation types), or enum declaration
FIELDUsed to describe a domain
METHODFor method
PARAMETERUsed to describe parameters
CONSTRUCTORUsed to describe constructors
LOCAL_VARIABLEUsed to describe local variables
ANNOTATION_TYPEUsed to describe annotations
PACKAGEUsed to describe the package
TYPE_PARAMETERIndicates that the annotation can be used in user-defined type parameters
TYPE_USEIs a comment on the type

So when you determine the scope of your annotation, you can paste @ target (SCOPE)!

Girlfriend: Oh, I see. Then I have a question, "what should I do if I want my subclass to inherit this annotation?"?

moon:!!!!!!! That's what I'm going to talk about!! 「@Inherited」 !! It is also one of the four meta annotations of java (the other three are @ target, @ retention, @ documented just mentioned)! Its function is to "let the child class inherit the annotation of the parent class". Do you know how to use it?

Girlfriend: points

moon: let me give you an example! Just practice!

Girlfriend: hum!

moon: let's write an annotation class first

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    /**
     * Say I love you (default true)
     */
    boolean sayILoveYou() default true;
}

moon: this annotation is very simple. "It can only work on methods. It is implemented at runtime. There is a syaILoveYou method. The default is true!"

Girlfriend: yue~ come on

moon: haha, define another me. There is a sayLoveYou() method, which pastes our @ MyAnnotation annotation to express my sincerity

public class Me {
    @MyAnnotation
    public void sayLoveYou(){
        System.out.println("Express my heart");
    }
}

Girlfriend: yue~

moon: OK, now let's start the test!

public class Main {
    public static void main(String[] args) {
        try {
            //Get the Class object of Me
            Me me = new Me();
            Class clazz = me.getClass();
            //Gets the annotation of the Info type on the sayLoveYou method of the object
            MyAnnotation myAnnotation = clazz.getMethod("sayLoveYou", null).getDeclaredAnnotation(MyAnnotation.class);
            if (myAnnotation.sayILoveYou()) {
                System.out.println("I love you!");
            } else {
                System.out.println("i don't love you");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

moon: we first get the Me object, and then get the annotation MyAnnotation. If MyAnnotation If sayiloveyou() is true, it will output "I love you"! If it is false, it will output "I don't love you"!

Girlfriend: you don't love me, "we break up"

moon: cough, test ~ let's run and have a look. The result must be that I love you! Because we default to true

moon: we modify the default value of the annotation, and the result is that I Emm love you (full of desire for survival)

public class Me {
    @MyAnnotation(sayILoveYou=false)
    public void sayLoveYou(){
        System.out.println("Express my heart");
    }
}

Girlfriend: hum~

moon: let's try the @ Inherited annotation again, modify MyAnnotation, "add @ Inherited", and add "add ElementType.TYPE and make it work on classes"

@Retention(RetentionPolicy.RUNTIME)
@Target({Ele,mentType.METHOD,ElementType.TYPE})
@Inherited
public @interface MyAnnotation {
    /**
     * Say I love you (default true)
     */
    boolean sayILoveYou() default true;
}

Moon: the class me is annotated with @ MyAnnotation on the class

@MyAnnotation
public class Me {
    public void sayLoveYou(){
        System.out.println("Express my heart");
    }
}

moon: then if we have children

public class Child extends Me{
}

Girlfriend: I won't marry you!

moon: hahaha, let's rewrite the Main method

public static void main(String[] args) {
   try {
       //Get the Class object of child
       Child child = new Child();
       Class clazz = child.getClass();
       //Gets the annotation of the Info type on the sayLoveYou method of the object
       MyAnnotation myAnnotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
       if (myAnnotation.sayILoveYou()) {
           System.out.println("I love you!");
       } else {
           System.out.println("i don't love you");
       }
   } catch (Exception e) {
       e.printStackTrace();
   }
}

moon: "at this time, our child object does not have @ MyAnnotation annotation annotation, but inherits from Me. However, because we pasted @ MyAnnotation annotation annotation and @ Inherited annotation on the Me class, the child also has the annotation function, so the running result must be I love you!"

moon: now you will! Annotation is so simple!

Girlfriend: hum, you're still useful. I don't need you anymore. Let's go

moon: good boss! (finally taught, I survived again)

How many times have you divided your hands? Have you counted them clearly?

Original address: Custom annotation, my girlfriend can!

Topics: Java Spring Spring Boot