@Constraint Custom Validation Type Comment

Posted by dw89 on Sun, 19 Sep 2021 18:53:19 +0200

/**
 * Bank card verification
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {StringChecker.class, ObjectChecker.class})
public @interface BankCard {

   String message() default "Bad format of bank card number";

   Class<?>[] groups() default {};

   Class<? extends Payload>[] payload() default {};

   /**
    * ConstraintValidator<A extends Annotation, T>
    *   A The first is a custom annotation class
    *   T The second is the type of data to validate
    *   For example, if a String is written, then this class only receives parameters of type String, and if a Long is written, it receives parameters of type Long...
    *   You can also write Object s, then this class receives all types of parameters, which can be distinguished by instanceof, for example, in the next class
    */
   class StringChecker implements ConstraintValidator<BankCard, String> {
      /**
       * Defined bank card number validation regular expression
       */
      private Pattern pattern = Pattern.compile("(^\d{19}$)");
      
      @Override
      public void initialize(BankCard constraintAnnotation) {
         // Initialization Method
         System.out.println("StringChecker init");
      }

      @Override
      public boolean isValid(String value, ConstraintValidatorContext context) {
         // Logical method of validation;value of String type here is the object that needs to be checked, it may be empty;
         // You can use @NotNull, @NotBlank, @NotEmpty, etc. to limit whether he is empty or not
         if (StringUtils.isEmpty(value)) {
            return true;
         }
         Matcher matcher = pattern.matcher(value);
         // matches exact match
         return matcher.matches();
      }
   }

   /**
    * Receive the field labeled by the @BankCard annotation, and as an Object, receive any type of
    */
   class ObjectChecker implements ConstraintValidator<BankCard, Object> {

      @Override
      public void initialize(BankCard constraintAnnotation) {
      }

      @Override
      public boolean isValid(Object value, ConstraintValidatorContext context) {
         if (null == value) {
            return true;
         }
         
         // Object type value, which can receive data of any data type
         if (value instanceof String) {
            System.out.println("It is String Value of type: " + value);
         } else if (value instanceof Long) {
            System.out.println("It is Long Value of type: " + value);
         } // Wait...
         
         return false;
      }
   }

}

In this custom validation comment above,
@Constraint(validatedBy = StringChecker.class)
Multiple can be defined in validatedBy, enclosed in {}, in which the StringChecker class handles logic of type String

This internal class can be defined externally for convenience

class StringChecker implements ConstraintValidator<BankCard, String> {}

With the @Constraint annotation, the ConstraintValidator interface must be implemented
There are two generics, the first is a custom annotation class, the second is the data type that needs to be validated. You can use Object to indicate that all types are supported and use different logical methods according to different types.

There are two methods in this interface, initialize and isValid.
The first is to initialize the validator, which is called by isValid.
The second is validation logic, where different logical methods are implemented.Returns true, then validation passes, false does not, and then throws a custom exception message inside the message.

In addition:

This custom annotation logic processing class, which implements the ConstraintValidator interface, is managed as a bean by spring by default, so it can inject other services into this logic processing class with @Autowiredu or @Resources, without annotating spring beans with @Compent on top of the class.

Custom Validation Type Annotation Class is usually added inside because it is used to validate data

String message() default "User does not exist or does not belong to the current organization";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

Remarks:

  • @Retention: Describes the life cycle of this annotation class. It has three parameters:
  • RetentionPolicy.SOURCE: Comments are kept in the source file only
  • RetentionPolicy.CLASS: Comments are retained in the class file and discarded when loaded into the JVM virtual machine
  • RetentionPolicy.RUNTIME: Comments are retained while the program is running, and all comments defined on a class can be obtained by reflection.
  • @Target: Used to indicate that the comment can be declared before those elements.
  • ElementType.TYPE: Indicates that the annotation can only be declared before a class.
  • ElementType.FIELD: Indicates that the annotation can only be declared before a field of a class.
  • ElementType.METHOD: Indicates that the annotation can only be declared before a class's method.
  • ElementType.PARAMETER: Indicates that the comment can only be declared before a method parameter.
  • ElementType.CONSTRUCTOR: Indicates that the comment can only be declared before the construction method of a class.
  • ElementType.LOCAL_VARIABLE: Indicates that the comment can only be declared before a local variable.
  • ElementType.ANNOTATION_TYPE: Indicates that the annotation can only be declared before one annotation type.
  • ElementType.PACKAGE: Indicates that the annotation can only be declared before a package name.

Topics: Java Spring regex