diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java index 0a19d5fffc..0915a50837 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java @@ -66,6 +66,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; * @author Dave Syer * @author Phillip Webb * @author Christian Dupuis + * @author Stephane Nicoll */ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware, @@ -322,13 +323,15 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc } private Validator determineValidator(Object bean) { + boolean globalValidatorSupportBean = (this.validator != null + && this.validator.supports(bean.getClass())); if (ClassUtils.isAssignable(Validator.class, bean.getClass())) { - if (this.validator == null) { + if (!globalValidatorSupportBean) { return (Validator) bean; } return new ChainingValidator(this.validator, (Validator) bean); } - return this.validator; + return globalValidatorSupportBean ? this.validator : null; } private PropertySources loadPropertySources(String[] locations, diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java index 3e7e57fcd7..e13accfa28 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java @@ -54,6 +54,7 @@ import static org.junit.Assert.fail; * * @author Christian Dupuis * @author Phillip Webb + * @author Stephane Nicoll */ public class ConfigurationPropertiesBindingPostProcessorTests { @@ -133,6 +134,39 @@ public class ConfigurationPropertiesBindingPostProcessorTests { this.context.refresh(); } + @Test + public void testValidationWithCustomValidator() { + this.context = new AnnotationConfigApplicationContext(); + this.context.register(TestConfigurationWithCustomValidator.class); + try { + this.context.refresh(); + fail("Expected exception"); + } + catch (BeanCreationException ex) { + BindException bex = (BindException) ex.getRootCause(); + assertEquals(1, bex.getErrorCount()); + } + } + + @Test + public void testValidationWithCustomValidatorNotSupported() { + MockEnvironment env = new MockEnvironment(); + env.setProperty("test.foo", "bar"); + this.context = new AnnotationConfigApplicationContext(); + this.context.setEnvironment(env); + this.context.register(TestConfigurationWithCustomValidator.class, + PropertyWithValidatingSetter.class); + try { + // PropertyWithValidatingSetter should not use validator + this.context.refresh(); + fail("Expected exception"); + } + catch (BeanCreationException ex) { + BindException bex = (BindException) ex.getRootCause(); + assertEquals(1, bex.getErrorCount()); + } + } + @Test public void testPropertyWithEnum() throws Exception { doEnumTest("test.theValue:foo"); @@ -373,6 +407,50 @@ public class ConfigurationPropertiesBindingPostProcessorTests { } + @Configuration + @EnableConfigurationProperties + public static class TestConfigurationWithCustomValidator { + + @Bean + public PropertyWithCustomValidator propertyWithCustomValidator() { + return new PropertyWithCustomValidator(); + } + + @Bean + public Validator configurationPropertiesValidator() { + return new CustomPropertyValidator(); + } + + } + + @ConfigurationProperties(prefix = "custom") + public static class PropertyWithCustomValidator { + + private String foo; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + } + + public static class CustomPropertyValidator implements Validator { + + @Override + public boolean supports(Class aClass) { + return aClass == PropertyWithCustomValidator.class; + } + + @Override + public void validate(Object o, Errors errors) { + ValidationUtils.rejectIfEmpty(errors, "foo", "TEST1"); + } + + } + @Configuration @EnableConfigurationProperties @ConfigurationProperties(prefix = "test", ignoreUnknownFields = false)