Close

Spring - Creating Custom Validation Constraint Annotation

[Updated: Jul 1, 2018, Created: Jun 29, 2018]

The custom constraint annotations (JSR 303/349/380) can be created as specified by the JavaBean validation specification (check out example here).

In spring if we register LocalValidatorFactoryBean to bootstrap javax.validation.ValidatorFactory then custom ConstraintValidator classes are loaded as Spring Bean. That means we can have benefit of Spring's dependency injection in validator classes.

Example

Creating custom constraint annotation

package com.logicbig.example;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
      ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = LanguageValidator.class)
public @interface Language {

  String message() default "must be a valid language display name," +
          " found: ${validatedValue}";

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

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

ConstraintValidator implementation

package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class LanguageValidator implements ConstraintValidator<Language, String> {
  @Autowired
  private LanguageProvider languageProvider;

  @Override
  public void initialize(Language constraintAnnotation) {
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
      if (value == null) {
          return false;
      }
      return languageProvider.getLanguages()
                             .stream()
                             .anyMatch(value::equalsIgnoreCase);
  }
}

As seen above we are injecting other spring bean in the validator class.

LanguageProvider bean

public interface LanguageProvider {

    List<String> getLanguages();

    @Component
    public static class DefaultLanguageProvider implements LanguageProvider {

        @Override
        public List<String> getLanguages() {
            List<String> languageList = new ArrayList<>();
            for (Locale locale : Locale.getAvailableLocales()) {
                languageList.add(locale.getDisplayLanguage());
            }
            return languageList;
        }
    }
}

Example POJO and Client Bean

public class Book {
  @NotNull
  private String name;
  @Language
  private String language;
    .............
}
@Component
public class ClientBean {
  @Autowired
  private Validator validator;

  public void run(){
      Book book = new Book();
      book.setName("Alien Explorer");
      book.setLanguage("Englis");

      Set<ConstraintViolation<Book>> violations = validator.validate(book);
      for (ConstraintViolation<Book> violation : violations) {
          String message = violation.getMessage();
          Path path = violation.getPropertyPath();
          System.err.println(path+" "+message);
      }
  }
}

JavaConfig and main class

@Configuration
@ComponentScan
public class AppConfig {
  @Bean
  public Validator validatorFactory() {
      return new LocalValidatorFactoryBean();
  }

  public static void main(String[] args) {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(
                      AppConfig.class);

      ClientBean bean = context.getBean(ClientBean.class);
      bean.run();
  }
}
language must be a valid language display name, found: Englis

Example Project

Dependencies and Technologies Used:

  • spring-context 5.0.7.RELEASE: Spring Context.
  • hibernate-validator 6.0.10.Final Hibernate Validator Engine - Relocation Artifact
  • javax.el 3.0.1-b09 Expression Language 3.0
  • JDK 10
  • Maven 3.5.4

Creating constraint annotation in Spring Core Select All Download
  • spring-custom-validation-constraints
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • Language.java

    See Also