Spring Boot - @ConfigurationProperties Validation by using JSR-303/349 Annotations

[Updated: Aug 14, 2017, Created: Aug 9, 2017]

In Spring Boot application, we can have @ConfigurationProperties classes validated via JSR-303/349 (Java EE Bean Validation specification) annotations. To make it work, we need to use Spring @Validated annotation on our configuration class. We also need to add a JSR-303/349 implementation in the classpath.

Example

Adding Hibernate validator dependency

In this example, we are going to use Hibernate validator (which is the reference implementation of JSR-303/349), so we have to add the related maven dependency:

pom.xml

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
</dependency>

Note that, we did not add the hibernate-validator version, that's because it is already configured in spring-boot-dependencies pom (which is the parent of spring-boot-starter-parent).

The external properties

src/main/resources/application.properties

spring.main.banner-mode=off 
spring.main.logStartupInfo=false
app.admin-contact-number=111-111-111
app.refresh-rate=0

@ConfigurationProperties class

@Component
@ConfigurationProperties("app")
@Validated
public class MyAppProperties {
  @Pattern(regexp = "\\d{3}-\\d{3}-\\d{4}")
  private String adminContactNumber;
  @Min(1)
  private int refreshRate;
    .............
}

Note that, we have added @Validated annotation to turn on the validation.

Also, we purposely added such values in the external properties files, which should fail per above validation annotations. We are doing that to see whether or not the validation is performed as expected.

The Main class

@SpringBootApplication
public class ExampleMain {

  public static void main(String[] args) throws InterruptedException {
      ConfigurableApplicationContext context = SpringApplication.run(ExampleMain.class, args);
      MyAppProperties bean = context.getBean(MyAppProperties.class);
      System.out.println(bean);
  }
}

Output

2017-08-09 15:01:32.304  INFO 14256 --- [mpleMain.main()] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4f1072ab: startup date [Wed Aug 09 15:01:32 CDT 2017]; root of context hierarchy
2017-08-09 15:01:32.572 WARN 14256 --- [mpleMain.main()] o.h.v.m.ParameterMessageInterpolator : HV000184: ParameterMessageInterpolator has been chosen, EL interpolation will not be supported
2017-08-09 15:01:32.636 WARN 14256 --- [mpleMain.main()] o.h.v.m.ParameterMessageInterpolator : HV000184: ParameterMessageInterpolator has been chosen, EL interpolation will not be supported
2017-08-09 15:01:32.706 ERROR 14256 --- [mpleMain.main()] o.s.b.b.PropertiesConfigurationFactory : Properties configuration failed validation
2017-08-09 15:01:32.707 ERROR 14256 --- [mpleMain.main()] o.s.b.b.PropertiesConfigurationFactory : Field error in object 'app' on field 'adminContactNumber': rejected value [111-111-111]; codes [Pattern.app.adminContactNumber,Pattern.adminContactNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.adminContactNumber,adminContactNumber]; arguments []; default message [adminContactNumber],[Ljavax.validation.constraints.Pattern$Flag;@57cd9090,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5f1d413f]; default message [must match "\d{3}-\d{3}-\d{4}"]
2017-08-09 15:01:32.707 ERROR 14256 --- [mpleMain.main()] o.s.b.b.PropertiesConfigurationFactory : Field error in object 'app' on field 'refreshRate': rejected value [0]; codes [Min.app.refreshRate,Min.refreshRate,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.refreshRate,refreshRate]; arguments []; default message [refreshRate],1]; default message [must be greater than or equal to 1]
2017-08-09 15:01:32.707 WARN 14256 --- [mpleMain.main()] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myAppProperties': Could not bind properties to MyAppProperties (prefix=app, ignoreInvalidFields=false, ignoreUnknownFields=true, ignoreNestedProperties=false); nested exception is org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 2 errors
Field error in object 'app' on field 'adminContactNumber': rejected value [111-111-111]; codes [Pattern.app.adminContactNumber,Pattern.adminContactNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.adminContactNumber,adminContactNumber]; arguments []; default message [adminContactNumber],[Ljavax.validation.constraints.Pattern$Flag;@57cd9090,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5f1d413f]; default message [must match "\d{3}-\d{3}-\d{4}"]
Field error in object 'app' on field 'refreshRate': rejected value [0]; codes [Min.app.refreshRate,Min.refreshRate,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.refreshRate,refreshRate]; arguments []; default message [refreshRate],1]; default message [must be greater than or equal to 1]
2017-08-09 15:01:32.711 INFO 14256 --- [mpleMain.main()] utoConfigurationReportLoggingInitializer :

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-08-09 15:01:32.713 ERROR 14256 --- [mpleMain.main()] o.s.b.d.LoggingFailureAnalysisReporter :

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target MyAppProperties{adminContactNumber='111-111-111', refreshRate=0} failed:

Property: app.adminContactNumber
Value: 111-111-111
Reason: must match "\d{3}-\d{3}-\d{4}"

Property: app.refreshRate
Value: 0
Reason: must be greater than or equal to 1


Action:

Update your application's configuration

[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:294)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myAppProperties': Could not bind properties to MyAppProperties (prefix=app, ignoreInvalidFields=false, ignoreUnknownFields=true, ignoreNestedProperties=false); nested exception is org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 2 errors
Field error in object 'app' on field 'adminContactNumber': rejected value [111-111-111]; codes [Pattern.app.adminContactNumber,Pattern.adminContactNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.adminContactNumber,adminContactNumber]; arguments []; default message [adminContactNumber],[Ljavax.validation.constraints.Pattern$Flag;@57cd9090,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5f1d413f]; default message [must match "\d{3}-\d{3}-\d{4}"]
Field error in object 'app' on field 'refreshRate': rejected value [0]; codes [Min.app.refreshRate,Min.refreshRate,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.refreshRate,refreshRate]; arguments []; default message [refreshRate],1]; default message [must be greater than or equal to 1]
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:334)
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:291)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
at com.logicbig.example.ExampleMain.main(ExampleMain.java:11)
... 6 more
Caused by: org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 2 errors
Field error in object 'app' on field 'adminContactNumber': rejected value [111-111-111]; codes [Pattern.app.adminContactNumber,Pattern.adminContactNumber,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.adminContactNumber,adminContactNumber]; arguments []; default message [adminContactNumber],[Ljavax.validation.constraints.Pattern$Flag;@57cd9090,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5f1d413f]; default message [must match "\d{3}-\d{3}-\d{4}"]
Field error in object 'app' on field 'refreshRate': rejected value [0]; codes [Min.app.refreshRate,Min.refreshRate,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [app.refreshRate,refreshRate]; arguments []; default message [refreshRate],1]; default message [must be greater than or equal to 1]
at org.springframework.boot.bind.PropertiesConfigurationFactory.checkForBindingErrors(PropertiesConfigurationFactory.java:359)
at org.springframework.boot.bind.PropertiesConfigurationFactory.doBindPropertiesToTarget(PropertiesConfigurationFactory.java:276)
at org.springframework.boot.bind.PropertiesConfigurationFactory.bindPropertiesToTarget(PropertiesConfigurationFactory.java:240)
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:329)
... 24 more

Example Project

Dependencies and Technologies Used :

  • spring-boot-starter 1.5.6.RELEASE: Core starter, including auto-configuration support, logging and YAML.
    Corresponding Spring version: 4.3.10.RELEASE
  • hibernate-validator 5.3.5.Final: Hibernate's Bean Validation (JSR-303) reference implementation.
  • JDK 1.8
  • Maven 3.3.9

@ConfigurationProperties Validation Example Select All Download
  • configuration-properties-validation
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources

See Also