diff --git a/eclipse/org.eclipse.jdt.ui.prefs b/eclipse/org.eclipse.jdt.ui.prefs index e207aa7230..c743db624d 100644 --- a/eclipse/org.eclipse.jdt.ui.prefs +++ b/eclipse/org.eclipse.jdt.ui.prefs @@ -70,7 +70,7 @@ org.eclipse.jdt.ui.keywordthis=false org.eclipse.jdt.ui.ondemandthreshold=9999 org.eclipse.jdt.ui.overrideannotation=true org.eclipse.jdt.ui.staticondemandthreshold=9999 -org.eclipse.jdt.ui.text.custom_code_templates= +org.eclipse.jdt.ui.text.custom_code_templates= sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true 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 628f346154..42766b7234 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 @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnResource; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.validation.MessageInterpolatorFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; @@ -51,7 +52,10 @@ public class ValidationAutoConfiguration { @Bean @ConditionalOnMissingBean public Validator validator() { - return new LocalValidatorFactoryBean(); + LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); + MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(); + factoryBean.setMessageInterpolator(interpolatorFactory.getObject()); + return factoryBean; } @Bean diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index df732b0055..7dde10b278 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -1,4 +1,6 @@ - + + 4.0.0 org.springframework.boot spring-boot-dependencies @@ -82,7 +84,7 @@ 3.7.1 1.1.3 5.2.5.Final - 5.2.4.Final + 5.3.4.Final 2.5.1 2.3.13 2.3.3 @@ -152,7 +154,7 @@ Ingalls-BUILD-SNAPSHOT 0.23.0.RELEASE 5.0.0.BUILD-SNAPSHOT - 1.1.1.RELEASE + 1.1.2.RELEASE 1.2.6.RELEASE 1.1.5.RELEASE 1.2.0.RELEASE @@ -1621,6 +1623,10 @@ xml-apis xml-apis + + javax.enterprise + cdi-api + @@ -1826,9 +1832,9 @@ ${mongodb.version} - org.mortbay.jasper - apache-el - ${jetty-el.version} + org.mortbay.jasper + apache-el + ${jetty-el.version} org.neo4j diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java index 4b84bf7fec..da5fd4aa93 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.boot.autoconfigure.web.ErrorAttributes; import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.boot.jackson.JsonComponent; import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter; @@ -54,6 +55,7 @@ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { includes.add(FilterRegistrationBean.class); includes.add(DelegatingFilterProxyRegistrationBean.class); includes.add(HandlerMethodArgumentResolver.class); + includes.add(ErrorAttributes.class); DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); }; diff --git a/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index 9262dd3797..43dcb55b0b 100644 --- a/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -74,7 +74,9 @@ org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration # DefaultTestExecutionListenersPostProcessors diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAllControllersIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAllControllersIntegrationTests.java index c5aa5e7d16..b737026799 100644 --- a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAllControllersIntegrationTests.java +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAllControllersIntegrationTests.java @@ -24,9 +24,11 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ErrorAttributes; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.isA; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -48,6 +50,9 @@ public class WebMvcTestAllControllersIntegrationTests { @Autowired private MockMvc mvc; + @Autowired(required = false) + private ErrorAttributes errorAttributes; + @Test public void shouldFindController1() throws Exception { this.mvc.perform(get("/one")).andExpect(content().string("one")) @@ -78,4 +83,10 @@ public class WebMvcTestAllControllersIntegrationTests { this.mvc.perform(get("/three/invalid")); } + @Test + public void shouldNotFilterErrorAttributes() throws Exception { + assertThat(this.errorAttributes).isNotNull(); + + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java index 9e711c4d89..3bf2c3d01e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java @@ -35,6 +35,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.boot.validation.MessageInterpolatorFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; @@ -400,7 +401,9 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc public Validator run(ApplicationContext applicationContext) { LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(); validator.setApplicationContext(applicationContext); + validator.setMessageInterpolator(interpolatorFactory.getObject()); validator.afterPropertiesSet(); return validator; } diff --git a/spring-boot/src/main/java/org/springframework/boot/validation/MessageInterpolatorFactory.java b/spring-boot/src/main/java/org/springframework/boot/validation/MessageInterpolatorFactory.java new file mode 100644 index 0000000000..9df5adc1b0 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/validation/MessageInterpolatorFactory.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2017 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.validation; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.validation.MessageInterpolator; +import javax.validation.Validation; +import javax.validation.ValidationException; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.util.ClassUtils; + +/** + * {@link ObjectFactory} that can be used to create a {@link MessageInterpolatorFactory}. + * Attempts to pick the most appropriate {@link MessageInterpolator} based on the + * classpath. + * + * @author Phillip Webb + */ +public class MessageInterpolatorFactory implements ObjectFactory { + + private static final Set FALLBACKS; + + static { + Set fallbacks = new LinkedHashSet(); + fallbacks.add("org.hibernate.validator.messageinterpolation" + + ".ParameterMessageInterpolator"); + FALLBACKS = Collections.unmodifiableSet(fallbacks); + } + + @Override + public MessageInterpolator getObject() throws BeansException { + try { + return Validation.byDefaultProvider().configure() + .getDefaultMessageInterpolator(); + } + catch (ValidationException ex) { + MessageInterpolator fallback = getFallback(); + if (fallback != null) { + return fallback; + } + throw ex; + } + } + + private MessageInterpolator getFallback() { + for (String fallback : FALLBACKS) { + try { + return getFallback(fallback); + } + catch (Exception ex) { + // Swallow an continue + } + } + return null; + } + + private MessageInterpolator getFallback(String fallback) { + Class interpolatorClass = ClassUtils.resolveClassName(fallback, null); + Object interpolator = BeanUtils.instantiate(interpolatorClass); + return (MessageInterpolator) interpolator; + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/validation/package-info.java b/spring-boot/src/main/java/org/springframework/boot/validation/package-info.java new file mode 100644 index 0000000000..f472911173 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/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. + */ + +/** + * Utilities and classes related to validation. + */ +package org.springframework.boot.validation; diff --git a/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryTests.java new file mode 100644 index 0000000000..e7e63f8c2d --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2017 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.validation; + +import javax.validation.MessageInterpolator; + +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link MessageInterpolatorFactory}. + * + * @author Phillip Webb + */ +public class MessageInterpolatorFactoryTests { + + @Test + public void getObjectShouldReturnResourceBundleMessageInterpolator() { + MessageInterpolator interpolator = new MessageInterpolatorFactory().getObject(); + assertThat(interpolator).isInstanceOf(ResourceBundleMessageInterpolator.class); + } + +} diff --git a/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryWithoutElIntegrationTests.java b/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryWithoutElIntegrationTests.java new file mode 100644 index 0000000000..e8fb801fb1 --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryWithoutElIntegrationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2017 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.validation; + +import javax.validation.MessageInterpolator; +import javax.validation.Validation; +import javax.validation.ValidationException; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import org.springframework.boot.junit.runner.classpath.ClassPathExclusions; +import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link MessageInterpolatorFactory} without EL. + * + * @author Phillip Webb + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions("tomcat-embed-el-*.jar") +public class MessageInterpolatorFactoryWithoutElIntegrationTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void defaultMessageInterpolatorShouldFail() throws Exception { + // Sanity test + this.thrown.expect(ValidationException.class); + this.thrown.expectMessage("javax.el.ExpressionFactory"); + Validation.byDefaultProvider().configure().getDefaultMessageInterpolator(); + } + + @Test + public void getObjectShouldUseFallback() { + MessageInterpolator interpolator = new MessageInterpolatorFactory().getObject(); + assertThat(interpolator).isInstanceOf(ParameterMessageInterpolator.class); + } + +}