Commit 5198fe88 authored by Andy Wilkinson's avatar Andy Wilkinson

Stop auto-config of MethodValidationPP triggering early init

Previously, if a user's configuration class provided a custom
Validator bean, that configuration class would be initialized very
early so that the Validator could be used to create the
auto-configured MethodValidationPostProcessor. This early
initialization could problems as it may prevent any of the
configuration class's dependencies from being post-processed.

This commit updates the injection of the Validator bean to be lazy,
thereby preventing the creation of the auto-configured
MethodValidationPostProcessor from triggering early initialization.

Closes gh-9416
parent 10a1cdfd
......@@ -29,6 +29,7 @@ import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role;
import org.springframework.core.env.Environment;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
......@@ -60,7 +61,7 @@ public class ValidationAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(
Environment environment, Validator validator) {
Environment environment, @Lazy Validator validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setProxyTargetClass(determineProxyTargetClass(environment));
processor.setValidator(validator);
......
......@@ -16,6 +16,9 @@
package org.springframework.boot.autoconfigure.validation;
import java.util.HashSet;
import java.util.Set;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.constraints.Min;
......@@ -27,12 +30,15 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfigurationTests.CustomValidatorConfiguration.TestBeanPostProcessor;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.CustomValidatorBean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
......@@ -198,6 +204,13 @@ public class ValidationAutoConfigurationTests {
.getPropertyValue("validator"));
}
@Test
public void methodValidationPostProcessorValidatorDependencyDoesNotTriggerEarlyInitialization() {
load(CustomValidatorConfiguration.class);
assertThat(this.context.getBean(TestBeanPostProcessor.class).postProcessed)
.contains("someService");
}
private boolean isPrimaryBean(String beanName) {
return this.context.getBeanDefinition(beanName).isPrimary();
}
......@@ -322,4 +335,53 @@ public class ValidationAutoConfigurationTests {
}
@Configuration
static class CustomValidatorConfiguration {
CustomValidatorConfiguration(SomeService someService) {
}
@Bean
Validator customValidator() {
return new CustomValidatorBean();
}
@Bean
static TestBeanPostProcessor testBeanPostProcessor() {
return new TestBeanPostProcessor();
}
@Configuration
static class SomeServiceConfiguration {
@Bean
public SomeService someService() {
return new SomeService();
}
}
static class SomeService {
}
static class TestBeanPostProcessor implements BeanPostProcessor {
private Set<String> postProcessed = new HashSet<String>();
@Override
public Object postProcessAfterInitialization(Object bean, String name) {
this.postProcessed.add(name);
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String name) {
return bean;
}
}
}
}
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