• Custom Validator in Spring MVC

    It may come a time that the existing validators are not sufficient for your needs. In this case you want to create your own validator annotation.

    Spring Custom Validator Annotation

    In this example, we’ll be creating a simple custom validator that will check if the username supplied in registration is already existing in the system. This assumes that you know the basics of form validators or if not please read first Spring MVC Form Validation

    1. Create Annotation Interface

      Create an annotation interface NotExistingUsername:

      @Target({ElementType.FIELD, ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Constraint(validatedBy = UsernameValidator.class)
      @Documented
      public @interface NotExistingUsername {
      
          String message() default "Username already exist";
      
          Class<?>[] groups() default {};
      
          Class<? extends Payload>[] payload() default {};
      }
      

      The above methods are required when creating custom validators.

      @Target({ElementType.FIELD, ElementType.TYPE})
      

      means that the annotation is applicable in class fields and in class or interface.

      @Retention(RetentionPolicy.RUNTIME)
      

      means that the annotation will be evaluated at runtime using reflection.

      @Constraint(validatedBy = UsernameValidator.class)
      

      this define the actual implementation of the interface.

      @Documented
      

      means that the annotation will be included in the javadoc

    2. Create the Implementing class

      Next we create the implementation class for NotExistingUsername interface. We create UsernameValidator.java

      @Component
      public class UsernameValidator implements ConstraintValidator<NotExistingUsername, String> {
      
          @Autowired private UserService userService;
      
          public void initialize(NotExistingUsername notExistingUsername) {
          }
      
          public boolean isValid(String username, ConstraintValidatorContext constraintValidatorContext) {
              return !userService.isUsernameExist(username);
          }
      }
      

      The class should implements the ConstraintValidator. The two generic parameter for ConstraintValidator is NotExistingUsername and String:

      ConstraintValidator<NotExistingUsername, String>
      

      The first generic is the annotation interface that this is bind to.
      The second generic is the type of object that will passed in this validator. Since we are validating the username, then its a string type.

      The method isValid is the one that will be called during the validation, so you add your logic here. In our case, we just let our UserService to handle if the username exist.

    3. Create Service

      This is optional and you can just add your logic in the validators. In our case, we create the UsernameService to check if the username is already existing in the system:

      @Service
      public class UserService {
      
          public boolean isUsernameExist(String username) {
              //for simplicity, we just check if the username is 'user'
              if (username.equals("user")) {
                  return true;
              }
              return false;
          }
      }
      

      This is just an example, and we only check that if the supplied username is “user”. In real life you may need to query your database to check.

    4. Add the Custom Validator in DTO

      Now that our custom validator is done, we can now add the annotation to our form object and annotate the field that we want to check.

      public class RegistrationDto {
      
          @NotExistingUsername
          private String username;
      
          @NotEmpty
          private String email;
      
          @Size(min = 5, max = 15)
          private String password;
      
          @Size(min = 5, max = 15)
          private String confirmPassword;
      
          public String getEmail() {
              return email;
          }
      
          public void setEmail(String email) {
              this.email = email;
          }
      
          public String getConfirmPassword() {
              return confirmPassword;
          }
      
          public void setConfirmPassword(String confirmPassword) {
              this.confirmPassword = confirmPassword;
          }
      
          public String getUsername() {
              return username;
          }
      
          public void setUsername(String username) {
              this.username = username;
          }
      
          public String getPassword() {
              return password;
          }
      
          public void setPassword(String password) {
              this.password = password;
          }
      }
      
    5. Testing Custom Validator

      Registering with username “user” should display the error message.

      spring custom validator

      spring custom validator

    You can download the source code here: custom-validator-example

    Related Post