diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java index e28cbd76bc4..752f7fbcc03 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/WebSocketAutoConfiguration.java @@ -21,6 +21,8 @@ import javax.servlet.Servlet; import org.apache.catalina.Context; import org.apache.catalina.deploy.ApplicationListener; import org.apache.catalina.startup.Tomcat; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -29,6 +31,7 @@ import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletCont import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.web.NonEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; @@ -47,6 +50,8 @@ import org.springframework.web.socket.WebSocketHandler; @AutoConfigureBefore(EmbeddedServletContainerAutoConfiguration.class) public class WebSocketAutoConfiguration { + private static Log logger = LogFactory.getLog(WebSocketAutoConfiguration.class); + private static final ApplicationListener WS_APPLICATION_LISTENER = new ApplicationListener( "org.apache.tomcat.websocket.server.WsContextListener", false); @@ -58,10 +63,14 @@ public class WebSocketAutoConfiguration { @Override public void customize(ConfigurableEmbeddedServletContainer container) { + if (container instanceof NonEmbeddedServletContainerFactory) { + logger.info("NonEmbeddedServletContainerFactory detected. Websockets support should be native so this normally is not a problem."); + return; + } if (!(container instanceof TomcatEmbeddedServletContainerFactory)) { throw new IllegalStateException( "Websockets are currently only supported in Tomcat (found " - + container.getClass() + ")"); + + container.getClass() + "). "); } ((TomcatEmbeddedServletContainerFactory) container) .addContextCustomizers(new TomcatContextCustomizer() { @@ -77,5 +86,4 @@ public class WebSocketAutoConfiguration { return customizer; } - } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/web/ErrorPageFilter.java b/spring-boot/src/main/java/org/springframework/boot/context/web/ErrorPageFilter.java index b36796f9dc5..de1828c8caf 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/web/ErrorPageFilter.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/web/ErrorPageFilter.java @@ -53,7 +53,7 @@ import org.springframework.stereotype.Component; @Component @Order(Ordered.HIGHEST_PRECEDENCE) class ErrorPageFilter extends AbstractConfigurableEmbeddedServletContainer implements - Filter { + Filter, NonEmbeddedServletContainerFactory { // From RequestDispatcher but not referenced to remain compatible with Servlet 2.5 diff --git a/spring-boot/src/main/java/org/springframework/boot/context/web/NonEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/web/NonEmbeddedServletContainerFactory.java new file mode 100644 index 00000000000..205e5d95609 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/context/web/NonEmbeddedServletContainerFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2013 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.context.web; + +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; + +/** + * Marker interface for {@link EmbeddedServletContainerFactory} types that are actually + * safe to run in a non-embedded container. + * + * @author Dave Syer + */ +public interface NonEmbeddedServletContainerFactory { + +} diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java index 2ee873e1cf1..d5142558d70 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java @@ -22,6 +22,7 @@ import javax.validation.constraints.NotNull; import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -33,6 +34,7 @@ import org.springframework.validation.Validator; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @@ -51,12 +53,28 @@ public class ConfigurationPropertiesBindingPostProcessorTests { } } + @Test + public void testValidationWithSetter() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, "test.foo:spam"); + this.context.register(TestConfigurationWithValidatingSetter.class); + try { + this.context.refresh(); + fail("Expected exception"); + } + catch (BeanCreationException ex) { + BindException bex = (BindException) ex.getRootCause(); + assertTrue(1 == bex.getErrorCount()); + } + } + @Test public void testValidationWithoutJSR303() { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfigurationWithoutJSR303.class); try { this.context.refresh(); + fail("Expected exception"); } catch (BeanCreationException ex) { BindException bex = (BindException) ex.getRootCause(); @@ -70,6 +88,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests { this.context.register(TestConfigurationWithJSR303.class); try { this.context.refresh(); + fail("Expected exception"); } catch (BeanCreationException ex) { BindException bex = (BindException) ex.getRootCause(); @@ -98,6 +117,35 @@ public class ConfigurationPropertiesBindingPostProcessorTests { this.context.refresh(); } + @Configuration + @EnableConfigurationProperties + public static class TestConfigurationWithValidatingSetter { + + @Bean + public PropertyWithValidatingSetter testProperties() { + return new PropertyWithValidatingSetter(); + } + + } + + @ConfigurationProperties(name = "test") + public static class PropertyWithValidatingSetter { + + private String foo; + + public String getFoo() { + return this.foo; + } + + public void setFoo(String foo) { + this.foo = foo; + if (!foo.equals("bar")) { + throw new IllegalArgumentException("Wrong value for foo"); + } + } + + } + @Configuration @EnableConfigurationProperties public static class TestConfigurationWithoutJSR303 {