From 990627b3288d274522ecf67a0933259ecc3b5970 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 31 May 2013 13:24:04 +0100 Subject: [PATCH] [bs-144] Make EmbedddedContainerConfiguration an import selector Previously EmbedddedContainerConfiguration cannot be imported directly. This change ensures that the nested classes are not loaded automatically so there can be no issues with the annotation parameters. There might be a case for a change in Spring here since the framework itself could just be more cautious when processing nested classes. [Fixes #50880927] --- ...onfigurationBootstrapApplicationTests.java | 92 +++++++++++++++++++ .../web/EmbeddedContainerConfiguration.java | 19 +++- 2 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 spring-bootstrap-samples/spring-bootstrap-tomcat-sample/src/test/java/org/springframework/bootstrap/sample/tomcat/NonAutoConfigurationBootstrapApplicationTests.java diff --git a/spring-bootstrap-samples/spring-bootstrap-tomcat-sample/src/test/java/org/springframework/bootstrap/sample/tomcat/NonAutoConfigurationBootstrapApplicationTests.java b/spring-bootstrap-samples/spring-bootstrap-tomcat-sample/src/test/java/org/springframework/bootstrap/sample/tomcat/NonAutoConfigurationBootstrapApplicationTests.java new file mode 100644 index 0000000000..097f071edb --- /dev/null +++ b/spring-bootstrap-samples/spring-bootstrap-tomcat-sample/src/test/java/org/springframework/bootstrap/sample/tomcat/NonAutoConfigurationBootstrapApplicationTests.java @@ -0,0 +1,92 @@ +package org.springframework.bootstrap.sample.tomcat; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.bootstrap.SpringApplication; +import org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerConfiguration; +import org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.bootstrap.sample.tomcat.service.HelloWorldService; +import org.springframework.bootstrap.sample.tomcat.web.SampleController; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.assertEquals; + +/** + * Basic integration tests for demo application. + * + * @author Dave Syer + * + */ +public class NonAutoConfigurationBootstrapApplicationTests { + + private static ConfigurableApplicationContext context; + + @Configuration + @Import({ EmbeddedContainerConfiguration.class, WebMvcAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class }) + @ComponentScan(basePackageClasses = { SampleController.class, HelloWorldService.class }) + public static class NonAutoConfigurationBootstrapApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(TomcatBootstrapApplication.class, args); + } + + } + + @BeforeClass + public static void start() throws Exception { + Future future = Executors + .newSingleThreadExecutor().submit( + new Callable() { + @Override + public ConfigurableApplicationContext call() throws Exception { + return (ConfigurableApplicationContext) SpringApplication + .run(NonAutoConfigurationBootstrapApplication.class); + } + }); + context = future.get(10, TimeUnit.SECONDS); + } + + @AfterClass + public static void stop() { + if (context != null) { + context.close(); + } + } + + @Test + public void testHome() throws Exception { + ResponseEntity entity = getRestTemplate().getForEntity( + "http://localhost:8080", String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals("Hello World", entity.getBody()); + } + + private RestTemplate getRestTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + } + }); + return restTemplate; + + } + +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerConfiguration.java index 627f26e473..3961558fbc 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerConfiguration.java @@ -28,7 +28,8 @@ import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServlet import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportSelector; +import org.springframework.core.type.AnnotationMetadata; /** * {@link EnableAutoConfiguration Auto-configuration} for an embedded servlet container. @@ -37,13 +38,21 @@ import org.springframework.context.annotation.Import; * @author Dave Syer * */ -@Import(ServerPropertiesConfiguration.class) -public class EmbeddedContainerConfiguration { +public class EmbeddedContainerConfiguration implements ImportSelector { + + @Override + public String[] selectImports(AnnotationMetadata importingClassMetadata) { + // Don't import the classes directly because that might trigger loading them - use + // an import selector and the class name instead + return new String[] { ServerPropertiesConfiguration.class.getName(), + EmbeddedJettyAutoConfiguration.class.getName(), + EmbeddedTomcatAutoConfiguration.class.getName() }; + } @Configuration @ConditionalOnClass({ Servlet.class, Server.class, Loader.class }) @ConditionalOnMissingBean(EmbeddedServletContainerFactory.class) - protected static class EmbeddedJettyAutoConfiguration { + public static class EmbeddedJettyAutoConfiguration { @Bean public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { @@ -55,7 +64,7 @@ public class EmbeddedContainerConfiguration { @Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class }) @ConditionalOnMissingBean(EmbeddedServletContainerFactory.class) - protected static class EmbeddedTomcatAutoConfiguration { + public static class EmbeddedTomcatAutoConfiguration { @Bean public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {