preface

Java has a magical existence, annotations, is that everyday @ other people’s guy, what is it holy ah?

Please first give the two masters to a key three, and then read on patiently, thank you.


What is annotation

Starting with JDK5, Java has added support for metadata, known as annotations. Annotations are distinct from annotations and can be thought of as special tokens in code that can be read at compile, class load, and run time and processed accordingly. Annotations allow developers to embed additional information in source code without changing the original code and logic.


Built-in annotations

In the IDE, if I create a class and implement an interface, the @override tag will automatically be added to the methods that implement the interface.

This tag is called an annotation. There are several built-in annotations like @Override in the JDK. They are all in the java.lang package.

@Override

When a subclass overrides a superclass method, a subclass can add this annotation, so what’s the use? This ensures that the subclass actually overrides the methods of the parent class, avoiding any low-level errors.

I didn’t know what to do with it until one day, I deleted this method from the interface, and it failed to compile.

Here are the results compiled directly from the command line. Now I know what this tag does. It tells the compiler and the source reader that this method overrides or implements a supertype.

@Deprecated

This annotation is used to indicate that a program element class, method, etc., is obsolete, and the compiler will warn other programs when they use an obsolete class or method (stridline, you’ve seen this a lot).

@SuppressWarnings

Suppress warnings.

package com.secondgod.annotation;

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List          objList = intList;
        objList.add("Two-headed."); }}Copy the code

Enable the compilation of recommended warnings on the command line. (The command is javac -d. -xLint test. Java.

With a small change in the code, compile warnings can be eliminated.

package com.secondgod.annotation;

import java.util.ArrayList;
import java.util.List;

public class Test {

    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List          objList = intList;
        objList.add("Two-headed."); }}Copy the code

@SafeVarargs

The Java compiler generates an unchecked warning when declaring constructors or methods that have variable parameters of fuzzy types such as generics. Given these circumstances, the Java compiler will not throw an unchecked warning if the programmer decides that the body of the declared constructor and method will not perform potentially unsafe operations on its varargs arguments by marking it with @safevarargs.

package com.secondgod.annotation;

import java.util.List;

public class Test {
    public final void test(List<String>... stringLists) {}}Copy the code

Enable compilation of recommended warnings on the command line.

With a small change in the code, compile warnings can be eliminated.

package com.secondgod.annotation;

import java.util.List;

public class Test {
    @SafeVarargs
    public final void test(List<String>... stringLists) {}}Copy the code

@FunctionalInterface

Functional interface annotations, a new feature introduced in Java 1.8. Functional programming is hot, so Java 8 added this feature just in time. What is the use of this annotation? This annotation ensures that the interface has only one abstract method. Note that this only decorates the interface.

  1. An interface with no abstract methods
package com.secondgod.annotation;

@FunctionalInterface
public interface Test {}Copy the code

  1. Interfaces that have more than one abstract method
package com.secondgod.annotation;

@FunctionalInterface
public interface Test {
    String test1(a);

    String test2(a);
}
Copy the code

  1. An interface with only one abstract method

The compilation passed.

package com.secondgod.annotation;

@FunctionalInterface
public interface Test {
    String test(a);
}
Copy the code
  1. An abstract class with only one abstract method
package com.secondgod.annotation;

@FunctionalInterface
public abstract class Test {
    public abstract String test(a);
}
Copy the code


Yuan notes

If we take a look at the @Override source code, we can see that the annotation definition itself has annotations, which are the annotations of annotations. People often call them meta-annotations. Meta annotations are annotations that are responsible for explaining other annotations and can be used to customize annotations.

The JDK’s built-in meta-annotations are found under the java.lang.Annotation package.

@Target

Target means Target, and @target specifies where the annotation will be used.

The values Scope of annotation
TYPE Can be used on a class or interface
FIELD Can be used on fields/fields/properties
METHOD Can be used for methods
PARAMETER Can be used on parameters
CONSTRUCTOR Can be used on constructors
LOCAL_VARIABLE Can be used on local variables
ANNOTATION_TYPE Can be used on annotation types (types decorated by @interface)
PACKAGE Used to record package information for Java files
TYPE_PARAMETER Can be used in declarations of type variables
TYPE_USE Can be used in any statement that uses a type

@Documented

An annotation class decorated with @Documented annotation is extracted as a document by the JavaDoc tool. JavaDoc does not include annotations by default, but if you specify @Documented when declaring an annotation, it is processed by a tool like JavaDoc, so the annotation type information is included in the generated help document.

@Inherited

Inherited means inheritance, but this does not mean that annotations themselves can inherit. This means that if a superclass is annotated by @inherited annotations, then a subclass of this class inherits the annotations of the superclass if no annotations are applied to it.

@Repeatable

Repeatable is the meaning of Repeatable. A new addition to Java 8, which allows you to repeat annotations within the same program element. The @repeatable annotation is often used when the same annotation needs to be used more than once. Prior to Java 8, no more than one annotation of the same type could precede a program element, and if you wanted to use multiple annotations of the same type before the same element, you had to use an annotation “container.”

@Retention

@Retention is used to describe the lifetime of an annotation, i.e. the length of time it is retained. @ the Retention of annotation member variables (value) is used to set up reserve strategy, the value is the Java lang. The annotation. RetentionPolicy enumerated types, RetentionPolicy have 3 enumerated constants, as shown below.

The values The life cycle
SOURCE Valid in the source file (available to the compiler)
CLASS Valid in class files (available to compilers and virtual machines)
RUNTIME Valid at run time (compiler, virtual machine, program run time)

@Native

Using the @native annotation to decorate a member variable means that the variable can be referenced by Native code and is often used by code generation tools. It’s also under the Java.lang. annotation package, but I don’t consider it a meta-annotation because it’s not intended to be used with annotations.


Custom annotations

There are annotations in Spring, Hibernate, Mybatis and other frameworks. Try to customize an annotation. Take a look at the @Override source code.

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since1.5 * /
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Copy the code

We’ll just do the same.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** * Test notes **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
Copy the code

Our custom annotations are usually defined with a lifecycle of RUNTIME. Life cycle for SOURCE, need to cooperate with the compiler. If the life cycle is CLASS, VMS are required. Only the behavior of the program at runtime is something we can customize.

Ok, go ahead and use this custom annotation.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** * Test notes **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}

/** * tests custom annotations **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    @MyAnnotation
    private String name;
}
Copy the code

Some annotations also take parameters, two owners also add.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** * Test notes **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String name(a);
}

/** * tests custom annotations **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    @myannotation (name = "2 master ")
    private String name;
}
Copy the code

Some annotations, such as @target, do not need to write the attribute name when assigning a value because the attribute name is “value”.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** * Test notes **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value(a);
}

/** * tests custom annotations **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    @myannotation (" two-master ")
    private String name;
}
Copy the code

When a property is defined in an annotation, it must be assigned a value where it is used. However, you can define default values in annotations, so you can use them without assigning values.

package com.secondgod.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** * Test notes **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value(a) default"Two-headed.";
}

/** * tests custom annotations **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    @MyAnnotation
    private String name;
}
Copy the code

The content in the annotation is very little, obviously its function is not implemented in it. So an annotation is just a tag and has no function of its own. So how does it function?


Annotation of actual combat

We used reflection and introspection with annotations to implement a gadget that automatically initializes properties with environment variables.

package com.secondgod.annotation;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/** * utility class **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class MyUtils {
    /** * Private construct, not instantiated */
    private MyUtils(a) {}

    /** * is used to initialize properties by default to the environment variable */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface EnvironmentVariables {
        /** * environment variable key *@return* /
        String value(a);
    }

    /** * get an instance of the class and initialize it with an environment variable@param clazz
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws java.beans.IntrospectionException
     * @throws InvocationTargetException
     */
    public static <T> T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException {
        T obj = clazz.newInstance();
        setEnvironmentVariables(obj);
        return obj;
    }

    /** * Assign object attributes to environment variables **@param o
     * @throws IllegalAccessException
     */
    public static void setEnvironmentVariables(Object o) throws IllegalAccessException, IntrospectionException, InvocationTargetException {
        for (Field f : o.getClass().getDeclaredFields()) {
            // Use reflection to read annotations
            EnvironmentVariables environmentVariables = f.getDeclaredAnnotation(EnvironmentVariables.class);
            if(environmentVariables ! =null) {
                // Read the environment variable if the annotation exists
                String value = System.getProperty(environmentVariables.value());
                // Write values using introspection
                PropertyDescriptor pd = newPropertyDescriptor(f.getName(), o.getClass()); pd.getWriteMethod().invoke(o, value); }}}}Copy the code

We define a class to represent information about the virtual machine and annotate the attribute fields with annotations.

package com.secondgod.annotation;

import java.text.MessageFormat;

/** * Vm information **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class VmInfo {
    @MyUtils.EnvironmentVariables(value = "java.vm.version")
    private String version;
    @MyUtils.EnvironmentVariables(value = "java.vm.vendor")
    private String vendor;
    @MyUtils.EnvironmentVariables(value = "java.vm.name")
    private String name;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.name")
    private String specName;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.vendor")
    private String specVendor;
    @MyUtils.EnvironmentVariables(value = "java.vm.specification.version")
    private String specVersion;
    @MyUtils.EnvironmentVariables(value = "java.vm.info")
    private String info;

    public String getVersion(a) {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getVendor(a) {
        return vendor;
    }

    public void setVendor(String vendor) {
        this.vendor = vendor;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSpecName(a) {
        return specName;
    }

    public void setSpecName(String specName) {
        this.specName = specName;
    }

    public String getSpecVendor(a) {
        return specVendor;
    }

    public void setSpecVendor(String specVendor) {
        this.specVendor = specVendor;
    }

    public String getSpecVersion(a) {
        return specVersion;
    }

    public void setSpecVersion(String specVersion) {
        this.specVersion = specVersion;
    }

    public String getInfo(a) {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public String toString(a) {
        return MessageFormat.format("Version={0}, Vendor={1}, name={2}, specName={3}, specVendor={4}, specVersion={5}, info={6}", version, vendor, name, specName, specVendor, specVendor, info); }}Copy the code

All right, let’s test our tool.

package com.secondgod.annotation;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;

/** * tests custom annotations **@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {

    public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException {
        VmInfo info1 = new VmInfo();
        System.out.println("After the common mode is instantiated:" + info1);
        VmInfo info2 = MyUtils.getInstance(VmInfo.class);
        System.out.println("Instantiated using our gadget:"+ info2); }}Copy the code

It’s a lot of content, it’s not fully cut, but it’s clear that our gadget is in line with our expectations, and it’s Nice.


The end of the

Custom annotations are available in frameworks like Spring, Hibernate, And Mybatis, and are often used as an alternative to configuration files. They each have their own advantages and disadvantages and should be chosen according to the actual situation. Configuration file changes restart the program, while annotation changes obviously only recompile. However, the second owners find it convenient and readable to have the configuration directly in use, so they prefer annotations unless there is a need for post-release modifications. However, using annotations will be more scattered than centralized configuration files. Well, that’s a matter of opinion.