Commit fbfbec11 authored by Stephane Nicoll's avatar Stephane Nicoll

Use custom validator on supported classes only

Previously, a customer was set regardless of the fact that it is
supported on the target bean. DataBinder has an actual assertion check
that would fail in such a case.

We now associate the custom validator only if it supports the target
bean.

Fixes gh-3581
parent a43cd18a
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -66,6 +66,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; ...@@ -66,6 +66,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author Christian Dupuis * @author Christian Dupuis
* @author Stephane Nicoll
*/ */
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware,
...@@ -321,13 +322,15 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc ...@@ -321,13 +322,15 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
} }
private Validator determineValidator(Object bean) { private Validator determineValidator(Object bean) {
boolean globalValidatorSupportBean = (this.validator != null
&& this.validator.supports(bean.getClass()));
if (ClassUtils.isAssignable(Validator.class, bean.getClass())) { if (ClassUtils.isAssignable(Validator.class, bean.getClass())) {
if (this.validator == null) { if (!globalValidatorSupportBean) {
return (Validator) bean; return (Validator) bean;
} }
return new ChainingValidator(this.validator, (Validator) bean); return new ChainingValidator(this.validator, (Validator) bean);
} }
return this.validator; return globalValidatorSupportBean ? this.validator : null;
} }
private PropertySources loadPropertySources(String[] locations, private PropertySources loadPropertySources(String[] locations,
......
...@@ -54,6 +54,7 @@ import static org.junit.Assert.fail; ...@@ -54,6 +54,7 @@ import static org.junit.Assert.fail;
* *
* @author Christian Dupuis * @author Christian Dupuis
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
public class ConfigurationPropertiesBindingPostProcessorTests { public class ConfigurationPropertiesBindingPostProcessorTests {
...@@ -133,6 +134,39 @@ public class ConfigurationPropertiesBindingPostProcessorTests { ...@@ -133,6 +134,39 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
this.context.refresh(); 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 @Test
public void testPropertyWithEnum() throws Exception { public void testPropertyWithEnum() throws Exception {
doEnumTest("test.theValue:foo"); doEnumTest("test.theValue:foo");
...@@ -373,6 +407,50 @@ public class ConfigurationPropertiesBindingPostProcessorTests { ...@@ -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 @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@ConfigurationProperties(prefix = "test", ignoreUnknownFields = false) @ConfigurationProperties(prefix = "test", ignoreUnknownFields = false)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment