From 5938df52eaad70ab80822664dbe57ae7f3724639 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Jul 2017 13:29:21 +0100 Subject: [PATCH] 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 --- .../ValidationAutoConfiguration.java | 3 +- .../ValidationAutoConfigurationTests.java | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java index 72be9fd7b44..f8ad76ed29f 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java @@ -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); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java index 49db8492e69..a937e88811d 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java @@ -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 { } + @org.springframework.context.annotation.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 postProcessed = new HashSet(); + + @Override + public Object postProcessAfterInitialization(Object bean, String name) { + this.postProcessed.add(name); + return bean; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String name) { + return bean; + } + + } + } + }