This article is based on JDK8. Annotations were introduced in JDK5, and later VERSIONS of the JDK have been extended. The annotations that are not specified in this article are those that JDK5 already supports.

: Notebook: This article has been filed to: “blog”

: Keyboard: The sample code in this article is archived in: “Javacore”

Introduction to the

The form of annotations

In Java, annotations are modifiers that start with the @ character. As follows:

@Override
void mySuperMethod(a) {... }Copy the code

Annotations can contain named or unnamed attributes, and these attributes have values.

@Author(
   name = "Benjamin Franklin",
   date = "3/27/2003"
)
class MyClass(a){... }Copy the code

If there is only one attribute named value, then the name can be omitted, as in:

@SuppressWarnings("unchecked")
void myMethod(a) {... }Copy the code

If an annotation has no attributes, it is called a tag annotation. Such as: @ Override.

What is annotation

Essentially, an annotation is a tag, which is essentially a special annotation that is no better than a normal annotation without the code to parse it.

Parsing an annotation usually takes two forms:

  • Direct scan at compile time – A compiler scan is when the compiler detects that a class or method is decorated with annotations while compiling bytecode to Java code, and it does some processing on those annotations. This applies only to the JDK’s built-in annotation classes.
  • Runtime reflection – If you want to customize an annotation, the Java compiler cannot recognize and process the annotation. It can only choose whether to compile it into a bytecode file based on the scope of the annotation. If you want to process an annotation, you must use reflection techniques to identify the annotation and the information it carries, and then process it accordingly.

The role of annotations

Annotations have many uses:

  • Compiler information – The compiler can use annotations to detect errors or suppress warnings.
  • Compile-time and deploy-time processing – programs can process annotation information to generate code, XML files, etc.
  • Runtime processing – Certain annotations can be examined and processed at runtime.

As Java programmers, you’ve all experienced the fear of being dominated by configuration files (XML, Properties) at some point. Too many configuration files can make a project difficult to maintain. In my opinion, using annotations to reduce the number of configuration files or code is the greatest use of annotations.

The cost of annotations

You win something, you lose something, and it’s the same with annotation technology. There is a cost to using annotations:

  • Obviously, it is intrusive programming, so there is a natural problem of increasing the degree of coupling.
  • Processing of custom annotations requires the use of reflection techniques to obtain properties at run time. If the element decorated by the annotation is a non-public member of the class, it can also be obtained by reflection. This violates the object – oriented encapsulation.
  • Problems caused by annotations are relatively difficult to debug or locate.

However, despite the flaws, the cost of annotations is acceptable compared to the functionality they provide.

The scope of the annotations

Annotations can be applied to declarations of classes, fields, methods, and other program elements.

Since JDK8, the application scope of annotations has been further expanded. Here are the new applications:

Class instance initialization expression:

new @Interned MyObject();
Copy the code

Type conversion:

myString = (@NonNull String) str;
Copy the code

Implementation interface declaration:

class UnmodifiableList<T> implements
    @Readonly ListThe < @Readonly T> {}
Copy the code

Throw an exception declaration:

void monitorTemperature(a)
    throws @Critical TemperatureException {}
Copy the code

Built-in annotations

The following annotations are built into the JDK:

  • @Override
  • @Deprecated
  • @SuppressWarnnings
  • @SafeVarargs(JDK7 introduced)
  • @FunctionalInterface(JDK8 introduced)

@Override

@OverrideUsed to indicate that a modified method overrides a method of a parent class.

The Java compiler alerts you if you try to use @override to flag a method that doesn’t actually Override the parent class.

@ Override example:

public class OverrideAnnotationDemo {

    static class Person {
        public String getName(a) {
            return "getName"; }}static class Man extends Person {
        @Override
        public String getName(a) {
            return "override getName";
        }

        /** * release the following comment. Compile time will alert */
       /* @Override public String getName2() { return "override getName2"; } * /
    }

    public static void main(String[] args) {
        Person per = newMan(); System.out.println(per.getName()); }}Copy the code

@Deprecated

@DeprecatedThis parameter is used to indicate that the modified class or class member or method is obsolete. This parameter is not recommended.

@Deprecated has some continuity: If we use an outdated class or class member in our code by inheritance or override, the compiler will still alert us even if the subclass or submethod is not marked @deprecated.

Note: There is a difference between the @Deprecated annotation type and the @Deprecated tag in Javadoc: the former is recognized by the Java compiler; The latter is identified by the Javadoc tool for generating documentation (containing descriptions of why a program member is obsolete and how it should be banned or replaced).

@ Deprecated example:

public class DeprecatedAnnotationDemo {
    static class DeprecatedField {
        @Deprecated
        public static final String DEPRECATED_FIELD = "DeprecatedField";
    }


    static class DeprecatedMethod {
        @Deprecated
        public String print(a) {
            return "DeprecatedMethod"; }}@Deprecated
    static class DeprecatedClass {
        public String print(a) {
            return "DeprecatedClass"; }}public static void main(String[] args) {
        System.out.println(DeprecatedField.DEPRECATED_FIELD);

        DeprecatedMethod dm = new DeprecatedMethod();
        System.out.println(dm.print());


        DeprecatedClass dc = newDeprecatedClass(); System.out.println(dc.print()); }}//Output:
//DeprecatedField
//DeprecatedMethod
//DeprecatedClass
Copy the code

@SuppressWarnnings

@SuppressWarningsUsed to turn off compile-time specific warnings for classes, methods, and members.

@SuppressWarning is not a tag annotation. It has an array member of type String[] that stores the type of alarm to close. For the Javac compiler, warning names that are valid for the -xLint option are also valid for @Suppresswarings, and the compiler will ignore unrecognized warning names.

@ SuppressWarning example:

@SuppressWarnings({"rawtypes"."unchecked"})
public class SuppressWarningsAnnotationDemo {
    static class SuppressDemo<T> {
        private T value;

        public T getValue(a) {
            return this.value;
        }

        public void setValue(T var) {
            this.value = var; }}@SuppressWarnings({"deprecation"})
    public static void main(String[] args) {
        SuppressDemo d = new SuppressDemo();
        d.setValue("Nanjing");
        System.out.println("Place:"+ d.getValue()); }}Copy the code

A brief description of common parameter values for the @suppresswarnings annotation:

  • deprecation– Warning when a deprecated class or method is used;
  • unchecked– Warnings when unchecked conversions are performed, such as specifying the type of collection to be saved without Generics when using the collection;
  • fallthrough– Warning when the Switch block goes straight to the next case without a Break;
  • path– Warning of nonexistent paths in classpath, source file path, etc.
  • serial– Warning when serialVersionUID definition is missing on serializable classes;
  • finally– A warning if any finally clause does not complete properly;
  • all– All warnings.
@SuppressWarnings({"uncheck"."deprecation"})
public class InternalAnnotationDemo {

    / * * *@SuppressWarningsFlag Clears alarms of the current type */
    @SuppressWarnings({"deprecation"})
    static class A {
        public void method1(a) {
            System.out.println("call method1");
        }

        / * * *@DeprecatedIndicates that the current method is deprecated. */ is not recommended
        @Deprecated
        public void method2(a) {
            System.out.println("call method2"); }}/ * * *@DeprecatedIndicates that the current class is obsolete. */ is not recommended
    @Deprecated
    static class B extends A {
        / * * *@OverrideThe tag shows a method */ that indicates that the current method overrides a parent class or interface
        @Override
        public void method1(a) {}}public static void main(String[] args) {
        A obj = newB(); obj.method1(); obj.method2(); }}Copy the code

@SafeVarargs

SafeVarargs introduced in JDK7.

@SafeVarargsTells the compiler that generics in variable-length arguments are type safe. Variable-length arguments are stored in arrays, and arrays and generics do not mix well.

Simply put, the data types of array elements are determined at compile time and at run time, whereas the data types of generic types are determined only at run time. Therefore, when a generic type is stored in an array, the compiler cannot verify that the data types match at compile time, so a warning message is given. That is, if the actual data type of the generic type does not match the type of the parameter array, a ClassCastException will result.

@safevarargs:

  • @SafeVarargsAnnotations can be used to construct methods.
  • @SafeVarargsAnnotations can be used forstaticfinalMethods.

@ SafeVarargs example:

public class SafeVarargsAnnotationDemo {
    /** * This method is actually not safe, do not use this annotation, compile alert */
    @SafeVarargs
    static void wrongMethod(List<String>... stringLists) {
        Object[] array = stringLists;
        List<Integer> tmpList = Arrays.asList(42);
        array[0] = tmpList; // Syntax error, but compilation does not alert
        String s = stringLists[0].get(0); // Run times ClassCastException
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");

        List<String> list2 = new ArrayList<>();
        list.add("1");
        list.add("2"); wrongMethod(list, list2); }}Copy the code

The above code, if not using @safevarargs, will be compiled with an alarm

[WARNING] /D:/Codes/ZP/Java/javacore/codes/basics/src/main/java/io/github/dunwu/javacore/annotation/SafeVarargsAnnotationDemo.java : Some input files use unchecked or unsafe operations. [WARNING] /D:/Codes/ZP/Java/javacore/codes/basics/src/main/java/io/github/dunwu/javacore/annotation/SafeVarargsAnnotationDemo.java : For details, use -xLint: Unchecked to recompile.Copy the code

@FunctionalInterface

@functionalInterface was introduced in JDK8.

@FunctionalInterfaceUsed to indicate that the interface being decorated is functional.

Note that if an interface conforms to the definition of a “FunctionalInterface”, it is ok not to add @functional interface; But if you write a non-functional interface and use @functionInterface instead, the compiler will report an error.

What is a functional interface?

A Functional Interface is an Interface that has one and only one abstract method, but can have multiple non-abstract methods. Functional interfaces can be implicitly converted to lambda expressions.

Features of functional interfaces:

  • An interface has one and only one abstract method (an abstract method has only a method definition, not a method body).
  • Public methods in class Object cannot be overridden in an interface (the compiler would also report an error).
  • The default implementation method is allowed.

Example:

public class FunctionalInterfaceAnnotationDemo {

    @FunctionalInterface
    public interface Func1<T> {
        void printMessage(T message);
    }

    / * * *@FunctionalInterfaceTwo abstract methods are defined in the modified interface. Error * is reported during compilation@param <T>
     */
    /*@FunctionalInterface public interface Func2
      
        { void printMessage(T message); void printMessage2(T message); } * /
      

    public static void main(String[] args) {
        Func1 func1 = message -> System.out.println(message);
        func1.printMessage("Hello");
        func1.printMessage(100); }}Copy the code

Yuan notes

There are a few annotations built into the JDK, but they are far from sufficient to meet the ever-changing needs encountered during development. So we need custom annotations, which requires meta-annotations.

The purpose of meta-annotations is to define other annotations.

Java provides the following meta-annotation types:

  • @Retention
  • @Target
  • @Documented
  • @Inherited(JDK8 introduced)
  • @Repeatable(JDK8 introduced)

These types and the classes they support can be found in the java.lang.Annotation package. Let’s take a look at what each meta-annotation does and how the corresponding parameters are used.

@Retention

@RetentionSpecifies the retention level for annotations.

@ Retention source code:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value(a);
}
Copy the code

RetentionPolicy is an enumeration type that defines the Retention level supported by @Retention modified annotations:

  • RetentionPolicy.SOURCEThe – tag’s annotations are valid only in the source file and are ignored by the compiler.
  • RetentionPolicy.CLASSThe JVM ignores the annotations of the – tag that are valid in the class file.
  • RetentionPolicy.RUNTIME– The annotations of the tag are valid at run time.

@ the Retention sample:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name(a) default "fieldName";
    public String setFuncName(a) default "setField";
    public String getFuncName(a) default "getField";
    public boolean defaultDBValue(a) default false;
}
Copy the code

@Documented

The @Documented indicates that whenever the specified annotation is used, the Javadoc should be used (by default, annotations are not included in the Javadoc). For more information, see the Javadoc Tools page.

@ Documented example:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    public String name(a) default "fieldName";
    public String setFuncName(a) default "setField";
    public String getFuncName(a) default "getField";
    public boolean defaultDBValue(a) default false;
}
Copy the code

@Target

@TargetSpecifies the type of element that an annotation can decorate.

@ Target source code:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}
Copy the code

ElementType is an enumeration type that defines the scope to which @Target-modified annotations can be applied:

  • ElementType.ANNOTATION_TYPE– The annotation of the tag can be applied to the annotation type.
  • ElementType.CONSTRUCTORThe annotation of the – tag can be applied to the constructor.
  • ElementType.FIELDThe annotations of the – tag can be applied to fields or attributes.
  • ElementType.LOCAL_VARIABLEThe annotations of the – tag can be applied to local variables.
  • ElementType.METHOD– The annotation of the tag can be applied to the method.
  • ElementType.PACKAGE– Tag annotations can be applied to package declarations.
  • ElementType.PARAMETER– Tag’s annotations can be applied to method parameters.
  • ElementType.TYPEThe annotations of the – tag can be applied to any element of the class.

@ Target example:

@Target(ElementType.TYPE)
public @interface Table {
    /** * Data table name annotation, default is class name *@return* /
    public String tableName(a) default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {}
Copy the code

@Inherited

@inherited means that annotation types can be Inherited (this is not the case by default).

Represents automatic inheritance of an annotation type. If the @inherited meta-annotation exists in the annotation type declaration, all subclasses of the class that the annotation decorates will inherit the annotation.

Note: The @inherited annotation type is Inherited by a subclass of the annotated class. Classes do not inherit annotations from the interfaces they implement, and methods do not inherit annotations from the methods they overwrite.

In addition, when @inherited type annotations have @retention as RetentionPolicy.RUNTIME, the reflection API enhances this inheritance. If we use java.lang.Reflect to query an annotation of type @inherited, the reflection code check will do the job: check the class and its parent until the specified annotation type is found, or reach the top level of the class inheritance structure.

@Inherited
public @interface Greeting {
    public enum FontColor{ BULE,RED,GREEN};
    String name(a);
    FontColor fontColor(a) default FontColor.GREEN;
}
Copy the code

@Repeatable

@RepeatableIndicates that annotations can be reused.

Take Spring @Scheduled as an example:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Schedules {
	Scheduled[] value();
}

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
  // ...
}
Copy the code

Application example:

public class TaskRunner {

    @Scheduled("0/15 * * *?")
    @Scheduled("0 0 12 *?")
    public void task1(a) {}}Copy the code

Custom annotations

When using the @ interface custom annotations, automatic inherited Java. Lang. The annotation. The annotation interface, the compiler automatically other details. When an annotation is defined, it cannot inherit from another annotation or interface. @interface is used to declare an annotation, where each method actually declares a configuration parameter. The name of the method is the name of the parameter, and the type of the returned value is the type of the parameter. (The type of the returned value can only be basic, Class, String, or enum.) You can declare the default value of the parameter by default.

Here, I’ll show you the full steps for custom annotations by implementing a regular validation annotation tool called RegexValid.

1. Definition of annotations

The syntax for annotations is as follows:

public @interfaceAnnotation name {body}Copy the code

Let’s define a note:

@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexValid {}
Copy the code

Description:

This is easy to understand from the previous section on the @Target, @Retention, and @Documented meta-annotations.

  • The code above defines a name called@RegexValidAnnotations.
  • @Documentedsaid@RegexValidYou should use Javadoc.
  • @Target({ElementType.FIELD, ElementType.PARAMETER})said@RegexValidCan be modified on class members or method parameters.
  • @ Retention (RetentionPolicy. RUNTIME)@RegexValidValid at run time.

At this point, we have defined an annotation that has no attributes, and at this point, it is just a tag annotation. As a regular tool, you can’t do anything without properties. Next, we’ll add an annotation property to it.

2. Annotate attributes

The syntax of the attribute is as follows:

[Access level modifier] [Data type] Name () default Default value;Copy the code

For example, if we want to define a string attribute in an annotation named value, whose default value is an empty string and whose access level is the default level, we should define it as follows:

String value() default "";
Copy the code

Note: In the annotation, when we define the property, we need to add () after the property name.

Defining an annotation attribute has the following key points:

  • Annotation properties can only be modified using public or the default access level (that is, no access level modifier is specified).

  • There are restrictions on the data type of the attribute. The following data types are supported:

    • All basic data types (byte, char, short, int, long, float, double, Boolean)
    • Type String
    • Class Class
    • Enum type
    • The Annotation type
    • All of the above types of arrays
  • The attribute must have a definite value. It is recommended to specify a default value. An annotation property can only be specified by default or when the annotation is used, which is more reliable than specifying a default value. The attribute cannot be null if it is a reference type. This constraint makes it difficult for the annotation handler to determine whether an annotation property is the default value or the property value specified when the annotation is used. To do this, when we set the default value, we usually define some special value, such as an empty string or a negative number.

  • If there is only one attribute value in the annotation, it is best to name it value. Because specifying the attribute name is value, the value specifying value can be used without specifying the attribute name.

// Both methods have the same effect
@RegexValid("^ ((\ \ +)? 86\\s*)? ([0-9] (13) | (15 ([0, 3] | [5-9])) | (18 [,2,5 0-9])) \ \ d {8} $")
@RegexValid(value = "^ ((\ \ +)? 86\\s*)? ([0-9] (13) | (15 ([0, 3] | [5-9])) | (18 [,2,5 0-9])) \ \ d {8} $")
Copy the code

Example:

With that in mind, let’s define a few attributes for the @Regexvalid annotation.

@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexValid {
    enum Policy {
        // @formatter:off
        EMPTY(null),
        DATE("^ (? : (? ! 0000) [0-9] {4} (/ - /.? (? : (? : 0? [1-9] | 1-2 0 and 3) 1 (\ \? : 0? [1-9] [0-9] | | 1 2 [0 to 8]) | (? : 0? [9] 13 - | 1 [2-0]) \ \ 1"
            + "(? 30) : 29 | | (? : 0? [13578] 1 [02]) \ \ | 1 (? : 31)) | (? : [0-9] {2} (? : 0 [48] | [2468] [048] | [13579] [26]) |"
            + "(? : 0 [48] | [2468] [048] | [13579] [26]) 00) (/ - /.? 0? 2 \ \ 2 (? : $29))"),
        MAIL("^[A-Za-z0-9](([_\\.\\-]? [a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\\.\\-]? [a-zA-Z0-9]+)*)\\.([A-Za-z]{2,})$");
        // @formatter:on

        private String policy;

        Policy(String policy) {
            this.policy = policy;
        }

        public String getPolicy(a) {
            returnpolicy; }}String value(a) default "";
    Policy policy(a) default Policy.EMPTY;
}
Copy the code

Description:

In the example code above, we define two attribute annotations: the Value attribute of the String type and the Policy attribute of the Policy enumeration type. The Policy enumeration defines several default regular expressions, which are used directly for regular validation. Given that we might need to pass in some custom regular expressions ourselves to validate other scenarios, we define the value attribute to allow the consumer to pass in regular expressions.

At this point, the @regexvalid statement is over. However, the program still doesn’t know how to handle the @Regexvalid annotation. We also need to define the annotation handler.

3. Annotation processor

Annotations are no more useful than annotations if there is no way and work to read them. An important part of the process of using annotations is the creation of an annotation handler. JDK5 extends the reflection API to help programmers quickly build custom annotation handlers.

Java. Lang. The annotation. The annotation is an interface, the program could be obtained by reflection of the specified program elements annotation object, and then through the metadata in the annotation object to obtain annotations.

The Annotation interface source code is as follows:

public interface Annotation {
    boolean equals(Object obj);

    int hashCode(a);

    String toString(a);

    Class<? extends Annotation> annotationType();
}
Copy the code

In addition, support Java annotation processor interface in Java. Lang. Reflect. AnnotatedElement, represent the interface program can accept annotations to program elements, the interface is mainly has the following several implementation class:

  • Class– class definition
  • Constructor– Constructor definition
  • Field– Tired member variable definition
  • Method– Method definition of the class
  • Package– The package definition of the class

The java.lang.reflect package mainly contains some tool classes to implement the reflection function. In fact, all the reflection apis provided by the java.lang.Reflect package extend the ability to read runtime annotation information. When an annotation type is defined as a runtime annotation, the annotation is visible to the runtime, and the annotation stored in the class file when the class file is loaded is read by the virtual machine. The AnnotatedElement interface is the parent interface for all program elements (Class, Method, and Constructor), so after the program gets the AnnotatedElement object for a Class through reflection, The program can then call one of the following four methods on the object to access the annotation information:

  • getAnnotation– Returns an annotation of the specified type that exists on the program element, or null if the annotation of the type does not exist.
  • getAnnotations– Returns all annotations that exist on the program element.
  • isAnnotationPresent– Determines whether the program element contains an annotation of the specified type, returning true if it does, false otherwise.
  • getDeclaredAnnotations– Returns all comments that exist directly on this element. Unlike other methods in this interface, this method ignores inherited comments. (If no comment exists directly on the element, an array of length zero is returned.) The caller of the method can modify the returned array at will; This has no effect on the arrays returned by other callers.

With that in mind, let’s implement @Regexvalid’s annotation handler:

import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexValidUtil {
    public static boolean check(Object obj) throws Exception {
        boolean result = true;
        StringBuilder sb = new StringBuilder();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            // Determines whether a member is decorated with the @regexValid annotation
            if (field.isAnnotationPresent(RegexValid.class)) {
                RegexValid valid = field.getAnnotation(RegexValid.class);

                // If value is an empty string, no custom regular expressions are injected. Use the policy attribute instead
                String value = valid.value();
                if ("".equals(value)) {
                    RegexValid.Policy policy = valid.policy();
                    value = policy.getPolicy();
                }

                // Access the private member by setting setAccessible(true)
                field.setAccessible(true);
                Object fieldObj = null;
                try {
                    fieldObj = field.get(obj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                if (fieldObj == null) {
                    sb.append("\n")
                        .append(String.format("The %s field in class %s cannot be empty!", obj.getClass().getName(), field.getName()));
                    result = false;
                } else {
                    if (fieldObj instanceof String) {
                        String text = (String) fieldObj;
                        Pattern p = Pattern.compile(value);
                        Matcher m = p.matcher(text);
                        result = m.matches();
                        if(! result) { sb.append("\n").append(String.format("%s is not legal %s!", text, field.getName())); }}else {
                        sb.append("\n").append(
                            String.format("The %s field in class %s is not a string type. This annotation cannot be used to verify!", obj.getClass().getName(), field.getName()));
                        result = false; }}}}if (sb.length() > 0) {
            throw new Exception(sb.toString());
        }
        returnresult; }}Copy the code

Description:

In the example above, the annotation handler performs the following steps:

  1. Gets all members of an incoming object through the getDeclaredFields reflection method.
  2. Iterate over the member, using isAnnotationPresent to determine if the member is decorated by the specified annotation, and if not, skip it.
  3. If the member is decorated by an annotation, passRegexValid valid = field.getAnnotation(RegexValid.class);The annotation instantiates the object in such a form that it can then be usedvalid.value()valid.policy()Gets the value of the property set in the annotation.
  4. Logical processing is performed based on the attribute value.

4. Use annotations

With that done, we can use custom annotations, as shown in the following example:

public class RegexValidDemo {
    static class User {
        private String name;
        @RegexValid(policy = RegexValid.Policy.DATE)
        private String date;
        @RegexValid(policy = RegexValid.Policy.MAIL)
        private String mail;
        @RegexValid("^ ((\ \ +)? 86\\s*)? ([0-9] (13) | (15 ([0, 3] | [5-9])) | (18 [,2,5 0-9])) \ \ d {8} $")
        private String phone;

        public User(String name, String date, String mail, String phone) {
            this.name = name;
            this.date = date;
            this.mail = mail;
            this.phone = phone;
        }

        @Override
        public String toString(a) {
            return "User{" + "name='" + name + '\' ' + ", date='" + date + '\' ' + ", mail='" + mail + '\' ' + ", phone='"
                + phone + '\' ' + '} '; }}static void printDate(@RegexValid(policy = RegexValid.Policy.DATE) String date){
        System.out.println(date);
    }

    public static void main(String[] args) throws Exception {
        User user = new User("Tom"."1990-01-31"."[email protected]"."18612341234");
        User user2 = new User("Jack"."2019-02-29"."sadhgs"."183xxxxxxxx");
        if (RegexValidUtil.check(user)) {
            System.out.println(user + "Regular check passed");
        }
        if (RegexValidUtil.check(user2)) {
            System.out.println(user2 + "Regular check passed"); }}}Copy the code

summary

The resources

  • Java Programming ideas
  • JAVA Core Technologies (Volume 1)
  • Effective java
  • This is an annotated version of an Oracle official document
  • A deeper understanding of Java: Annotations get you started on custom annotations
  • Blog.csdn.net/briblue/art…