From 9104ea81e82094e27ca71c64de05c40164bee1a6 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 19 Dec 2016 14:06:17 +0100 Subject: [PATCH] Expose Validator bean This commit improves ValidationAutoConfiguration so that a `Validator` bean is exposed if JSR 303 is available. This has the side effect of automatically enable Spring Data Couchbase's entity validation rather than requiring to expose a `Validator` bean. Closes gh-5178 --- .../CouchbaseDataAutoConfiguration.java | 8 ++++-- .../ValidationAutoConfiguration.java | 18 +++++++++--- .../CouchbaseDataAutoConfigurationTests.java | 28 ++++--------------- .../ValidationAutoConfigurationTests.java | 10 ++++++- ...hHibernateValidatorMissingElImplTests.java | 3 ++ ...utoConfigurationWithoutValidatorTests.java | 3 ++ 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java index 578da11114..9360dcfcfc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java @@ -22,9 +22,10 @@ import com.couchbase.client.java.Bucket; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,7 +42,8 @@ import org.springframework.data.couchbase.repository.CouchbaseRepository; */ @Configuration @ConditionalOnClass({ Bucket.class, CouchbaseRepository.class }) -@AutoConfigureAfter(CouchbaseAutoConfiguration.class) +@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, + ValidationAutoConfiguration.class }) @EnableConfigurationProperties(CouchbaseDataProperties.class) @Import({ CouchbaseConfigurerAdapterConfiguration.class, SpringBootCouchbaseDataConfiguration.class }) @@ -52,7 +54,7 @@ public class CouchbaseDataAutoConfiguration { public static class ValidationConfiguration { @Bean - @ConditionalOnBean(Validator.class) + @ConditionalOnSingleCandidate(Validator.class) public ValidatingCouchbaseEventListener validationEventListener( Validator validator) { return new ValidatingCouchbaseEventListener(validator); 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 0aefeda100..b25d883443 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 @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.validation; import javax.validation.Validation; +import javax.validation.Validator; import javax.validation.executable.ExecutableValidator; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -32,6 +33,7 @@ import org.springframework.context.annotation.Conditional; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; /** @@ -42,14 +44,22 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess * @since 1.5.0 */ @ConditionalOnClass(ExecutableValidator.class) +@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider") +@Conditional(ValidationAutoConfiguration.OnValidatorAvailableCondition.class) public class ValidationAutoConfiguration { @Bean - @ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider") - @Conditional(OnValidatorAvailableCondition.class) @ConditionalOnMissingBean - public MethodValidationPostProcessor methodValidationPostProcessor() { - return new MethodValidationPostProcessor(); + public Validator validator() { + return new LocalValidatorFactoryBean(); + } + + @Bean + @ConditionalOnMissingBean + public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) { + MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); + processor.setValidator(validator); + return processor; } @Order(Ordered.LOWEST_PRECEDENCE) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java index b379ad6274..8f8bb415ae 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java @@ -18,20 +18,17 @@ package org.springframework.boot.autoconfigure.data.couchbase; import java.util.Set; -import javax.validation.Validator; - import org.junit.After; import org.junit.Test; -import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfigurer; import org.springframework.boot.autoconfigure.data.couchbase.city.City; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; 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.Import; import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; @@ -44,7 +41,6 @@ import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; /** * Tests for {@link CouchbaseDataAutoConfiguration}. @@ -79,11 +75,9 @@ public class CouchbaseDataAutoConfigurationTests { @Test public void validatorIsPresent() { - load(ValidatorConfiguration.class); - ValidatingCouchbaseEventListener listener = this.context - .getBean(ValidatingCouchbaseEventListener.class); - assertThat(new DirectFieldAccessor(listener).getPropertyValue("validator")) - .isEqualTo(this.context.getBean(Validator.class)); + load(CouchbaseTestConfigurer.class); + assertThat(this.context.getBeansOfType(ValidatingCouchbaseEventListener.class)) + .hasSize(1); } @Test @@ -132,22 +126,12 @@ public class CouchbaseDataAutoConfigurationTests { context.register(config); } context.register(PropertyPlaceholderAutoConfiguration.class, - CouchbaseAutoConfiguration.class, CouchbaseDataAutoConfiguration.class); + ValidationAutoConfiguration.class, CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class); context.refresh(); this.context = context; } - @Configuration - @Import(CouchbaseTestConfigurer.class) - static class ValidatorConfiguration { - - @Bean - public Validator myValidator() { - return mock(Validator.class); - } - - } - @Configuration static class CustomCouchbaseConfiguration extends AbstractCouchbaseDataConfiguration { 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 3d8c803800..8bec1437e8 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 @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.validation; import javax.validation.ConstraintViolationException; +import javax.validation.Validator; import javax.validation.constraints.Size; import org.junit.After; @@ -24,6 +25,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -54,6 +56,7 @@ public class ValidationAutoConfigurationTests { @Test public void validationIsEnabled() { load(SampleService.class); + assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1); SampleService service = this.context.getBean(SampleService.class); service.doSomething("Valid"); this.thrown.expect(ConstraintViolationException.class); @@ -63,10 +66,15 @@ public class ValidationAutoConfigurationTests { @Test public void userDefinedMethodValidationPostProcessorTakesPrecedence() { load(SampleConfiguration.class); + assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1); + Object userMethodValidationPostProcessor = + this.context.getBean("testMethodValidationPostProcessor"); assertThat(this.context.getBean(MethodValidationPostProcessor.class)) - .isSameAs(this.context.getBean("testMethodValidationPostProcessor")); + .isSameAs(userMethodValidationPostProcessor); assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)) .hasSize(1); + assertThat(this.context.getBean(Validator.class)).isNotSameAs( + new DirectFieldAccessor(userMethodValidationPostProcessor).getPropertyValue("validator")); } public void load(Class config) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests.java index 1ecf585400..e4d124c37b 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.validation; +import javax.validation.Validator; + import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,6 +52,7 @@ public class ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests public void validationIsDisabled() { this.context = new AnnotationConfigApplicationContext( ValidationAutoConfiguration.class); + assertThat(this.context.getBeansOfType(Validator.class)).isEmpty(); assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)) .isEmpty(); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithoutValidatorTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithoutValidatorTests.java index 963c2f3787..53b7568e19 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithoutValidatorTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationWithoutValidatorTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.validation; +import javax.validation.Validator; + import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +51,7 @@ public class ValidationAutoConfigurationWithoutValidatorTests { public void validationIsDisabled() { this.context = new AnnotationConfigApplicationContext( ValidationAutoConfiguration.class); + assertThat(this.context.getBeansOfType(Validator.class)).isEmpty(); assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)) .isEmpty(); }