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 new file mode 100644 index 0000000000..766fbf15ea --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.validation; + +import javax.validation.Validator; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnResource; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +/** + * {@link EnableAutoConfiguration Auto-configuration} to configure the validation + * infrastructure. + * + * @author Stephane Nicoll + * @since 1.5.0 + */ +@ConditionalOnClass({ Validator.class }) +public class ValidationAutoConfiguration { + + @Bean + @ConditionalOnResource(resources = "META-INF/services/javax.validation.spi.ValidationProvider") + @ConditionalOnMissingBean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/package-info.java new file mode 100644 index 0000000000..5f0fa4facf --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/validation/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Auto-configuration for (JSR-303) Validation. + */ +package org.springframework.boot.autoconfigure.validation; 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 new file mode 100644 index 0000000000..f03f2db8c4 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidationAutoConfigurationTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.validation; + +import javax.validation.ConstraintViolationException; +import javax.validation.constraints.Size; + +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.annotation.Validated; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ValidationAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class ValidationAutoConfigurationTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void validationIsEnabled() { + load(SampleService.class); + SampleService service = this.context.getBean(SampleService.class); + service.doSomething("Valid"); + this.thrown.expect(ConstraintViolationException.class); + service.doSomething("KO"); + } + + @Test + public void userDefinedMethodValidationPostProcessorTakesPrecedence() { + load(SampleConfiguration.class); + assertThat(this.context.getBean(MethodValidationPostProcessor.class)) + .isSameAs(this.context.getBean("testMethodValidationPostProcessor")); + assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class)).hasSize(1); + } + + public void load(Class config) { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + if (config != null) { + applicationContext.register(config); + } + applicationContext.register(ValidationAutoConfiguration.class); + applicationContext.refresh(); + this.context = applicationContext; + } + + @Validated + static class SampleService { + + public void doSomething(@Size(min = 3, max = 10) String name) { + + } + } + + @Configuration + static class SampleConfiguration { + + @Bean + public MethodValidationPostProcessor testMethodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + } + +} diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index c2ca8612e6..c8b29eecd5 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4616,6 +4616,34 @@ Lastly, the most extreme (and rarely used) option is to create your own +[[boot-features-validation]] +== Validation +The method validation feature supported by Bean Validation 1.1 is automatically enabled +as long as a JSR-303 implementation (e.g. Hibernate validator) is on the classpath. This +allows bean methods to be annotated with `javax.validation` constraints on their +parameters and/or on their return value. Target classes with such annotated methods need +to be annotated with the `@Validated` annotation at the type level for their methods to +be searched for inline constraint annotations. + +For instance, the following service triggers the validation of the first argument, making +sure its size is between 8 and 10 + +[source,java,indent=0] +---- + @Service + @Validated + public class MyBean { + + public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, + Author author) { + ... + } + + } +---- + + + [[boot-features-email]] == Sending email The Spring Framework provides an easy abstraction for sending email using the