diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/MessageSourceAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/MessageSourceAutoConfiguration.java index 8a3fa9e81a..30b3ad72c0 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/MessageSourceAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/MessageSourceAutoConfiguration.java @@ -23,6 +23,8 @@ import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}. @@ -31,6 +33,7 @@ import org.springframework.context.support.ResourceBundleMessageSource; */ @Configuration @ConditionalOnMissingBean(MessageSource.class) +@Order(Ordered.HIGHEST_PRECEDENCE) public class MessageSourceAutoConfiguration { @Value("${spring.messages.basename:messages}") diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/PropertyPlaceholderAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/PropertyPlaceholderAutoConfiguration.java index 5f89f78397..ea5a556ac9 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/PropertyPlaceholderAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/PropertyPlaceholderAutoConfiguration.java @@ -16,11 +16,14 @@ package org.springframework.bootstrap.autoconfigure; +import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; /** * {@link EnableAutoConfiguration Auto-configuration} for @@ -30,9 +33,11 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; * @author Dave Syer */ @Configuration +@Order(Ordered.HIGHEST_PRECEDENCE) public class PropertyPlaceholderAutoConfiguration { @Bean + @ConditionalOnMissingBean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer( ApplicationContext context) { return new PropertySourcesPlaceholderConfigurer(); diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigureRegistrar.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigureRegistrar.java index 08fde0753f..14052ff78b 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigureRegistrar.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigureRegistrar.java @@ -25,7 +25,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils; +import org.springframework.bootstrap.autoconfigure.AutoConfigurationUtils; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/jdbc/DataSourceAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/jdbc/DataSourceAutoConfiguration.java index aaba3b9348..486c5fa14c 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/jdbc/DataSourceAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/jdbc/DataSourceAutoConfiguration.java @@ -206,7 +206,6 @@ public class DataSourceAutoConfiguration { } return super.matches(context, metadata); } - } static abstract class NonEmbeddedDatabaseCondition implements Condition { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java index 31ee1a97f0..6db6ba0633 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java @@ -25,7 +25,6 @@ import org.springframework.bootstrap.context.annotation.ConditionalOnClass; import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -42,7 +41,6 @@ import org.springframework.util.StringUtils; @Configuration @ConditionalOnClass(HibernateEntityManager.class) @EnableTransactionManagement -@Import(JpaComponentScanDetector.class) public class HibernateJpaAutoConfiguration extends JpaAutoConfiguration { public static enum DDLAUTO { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/JpaAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/JpaAutoConfiguration.java index c762a15a23..3684af0bce 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/JpaAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/orm/jpa/JpaAutoConfiguration.java @@ -27,8 +27,8 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.bootstrap.autoconfigure.AutoConfigurationUtils; import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration; -import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils; import org.springframework.bootstrap.context.annotation.ConditionalOnBean; import org.springframework.bootstrap.context.annotation.ConditionalOnClass; import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 6eddfce2b2..8a7f88ef90 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -27,6 +27,8 @@ import nz.net.ultraq.web.thymeleaf.LayoutDialect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.bootstrap.context.annotation.AutoConfigureAfter; import org.springframework.bootstrap.context.annotation.ConditionalOnClass; import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; import org.springframework.bootstrap.context.annotation.ConditionalOnMissingClass; @@ -49,6 +51,7 @@ import org.thymeleaf.templateresolver.TemplateResolver; */ @Configuration @ConditionalOnClass(SpringTemplateEngine.class) +@AutoConfigureAfter(WebMvcAutoConfiguration.class) public class ThymeleafAutoConfiguration { @Configuration diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerCustomizerConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerCustomizerConfiguration.java deleted file mode 100644 index 4069b46372..0000000000 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerCustomizerConfiguration.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.bootstrap.autoconfigure.web; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import javax.servlet.Servlet; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.bootstrap.context.annotation.ConditionalOnClass; -import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; -import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; -import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for - * {@link EmbeddedServletContainerCustomizer}. - * - * @author Dave Syer - */ -@Configuration -@ConditionalOnClass({ Servlet.class, EmbeddedServletContainerCustomizer.class }) -public class EmbeddedContainerCustomizerConfiguration { - - @Bean - public BeanPostProcessor embeddedContainerCustomizerBeanPostProcessor( - ListableBeanFactory beanFactory) { - // Look these up, not autowired because we don't want the ones from the parent - // context - Collection customizers = beanFactory - .getBeansOfType(EmbeddedServletContainerCustomizer.class).values(); - return new EmbeddedContainerCustomizerBeanPostProcessor(customizers); - } - - private static final class EmbeddedContainerCustomizerBeanPostProcessor implements - BeanPostProcessor { - - private List customizers; - - public EmbeddedContainerCustomizerBeanPostProcessor( - Collection customizers) { - final List list = new ArrayList( - customizers); - Collections.sort(list, new AnnotationAwareOrderComparator()); - this.customizers = list; - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof ConfigurableEmbeddedServletContainerFactory) { - ConfigurableEmbeddedServletContainerFactory factory = (ConfigurableEmbeddedServletContainerFactory) bean; - for (EmbeddedServletContainerCustomizer customizer : this.customizers) { - customizer.customize(factory); - } - } - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } - } - -} 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/EmbeddedServletContainerAutoConfiguration.java similarity index 52% rename from spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedContainerConfiguration.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java index 62f39cf036..7d4e6cdd6e 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/EmbeddedServletContainerAutoConfiguration.java @@ -24,47 +24,59 @@ import org.eclipse.jetty.util.Loader; import org.springframework.bootstrap.context.annotation.ConditionalOnClass; import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; +import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.bootstrap.context.embedded.ServletContextInitializer; import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory; 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.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.web.servlet.DispatcherServlet; /** - * {@link EnableAutoConfiguration Auto-configuration} for an embedded servlet container. + * {@link EnableAutoConfiguration Auto-configuration} for an embedded servlet containers. * * @author Phillip Webb * @author Dave Syer */ -public class EmbeddedContainerConfiguration implements ImportSelector { +@Order(Ordered.HIGHEST_PRECEDENCE) +public class EmbeddedServletContainerAutoConfiguration { - @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() }; + /** + * Support {@link EmbeddedServletContainerCustomizerBeanPostProcessor} to apply + * {@link EmbeddedServletContainerCustomizer}s. + */ + @Bean + @ConditionalOnMissingBean(value = EmbeddedServletContainerCustomizerBeanPostProcessor.class, considerHierarchy = false) + public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContainerCustomizerBeanPostProcessor() { + return new EmbeddedServletContainerCustomizerBeanPostProcessor(); } - @Configuration - @ConditionalOnClass({ Servlet.class, Server.class, Loader.class }) - @ConditionalOnMissingBean(EmbeddedServletContainerFactory.class) - public static class EmbeddedJettyAutoConfiguration { + /** + * Add the {@link DispatcherServlet} unless the user has defined their own + * {@link ServletContextInitializer}s. + */ + @ConditionalOnClass(DispatcherServlet.class) + public static class DispatcherServletConfiguration { @Bean - public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { - return new JettyEmbeddedServletContainerFactory(); + @ConditionalOnMissingBean(value = { ServletContextInitializer.class, + Servlet.class }, considerHierarchy = false) + public DispatcherServlet dispatcherServlet() { + return new DispatcherServlet(); } - } + /** + * Nested configuration for if Tomcat is being used. + */ @Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class }) - @ConditionalOnMissingBean(EmbeddedServletContainerFactory.class) - public static class EmbeddedTomcatAutoConfiguration { + @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, considerHierarchy = false) + public static class EmbeddedTomcat { @Bean public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { @@ -73,4 +85,19 @@ public class EmbeddedContainerConfiguration implements ImportSelector { } + /** + * Nested configuration if Jetty is being used. + */ + @Configuration + @ConditionalOnClass({ Servlet.class, Server.class, Loader.class }) + @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, considerHierarchy = false) + public static class EmbeddedJetty { + + @Bean + public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { + return new JettyEmbeddedServletContainerFactory(); + } + + } + } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesAutoConfiguration.java similarity index 80% rename from spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfiguration.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesAutoConfiguration.java index 839d664e4b..7d9c69b9f8 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesAutoConfiguration.java @@ -18,21 +18,23 @@ package org.springframework.bootstrap.autoconfigure.web; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.RemoteIpValve; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.BeansException; import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; +import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; import org.springframework.bootstrap.context.annotation.EnableConfigurationProperties; import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.bootstrap.properties.ServerProperties; import org.springframework.bootstrap.properties.ServerProperties.Tomcat; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; /** - * {@link EmbeddedServletContainerCustomizer} that configures the + * {@link EnableAutoConfiguration Auto-configuration} that configures the * {@link ConfigurableEmbeddedServletContainerFactory} from a {@link ServerProperties} * bean. * @@ -40,22 +42,28 @@ import org.springframework.util.StringUtils; */ @Configuration @EnableConfigurationProperties -public class ServerPropertiesConfiguration implements EmbeddedServletContainerCustomizer { +public class ServerPropertiesAutoConfiguration implements + EmbeddedServletContainerCustomizer, ApplicationContextAware { - @Autowired - private BeanFactory beanFactory; + private ApplicationContext applicationContext; - @ConditionalOnMissingBean(ServerProperties.class) @Bean(name = "org.springframework.bootstrap.properties.ServerProperties") + @ConditionalOnMissingBean public ServerProperties serverProperties() { return new ServerProperties(); } + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + @Override public void customize(ConfigurableEmbeddedServletContainerFactory factory) { // Need to do a look up here to make it lazy - ServerProperties server = this.beanFactory.getBean(ServerProperties.class); + ServerProperties server = this.applicationContext.getBean(ServerProperties.class); factory.setPort(server.getPort()); factory.setAddress(server.getAddress()); diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfiguration.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfiguration.java index 433eb9ee0d..232815d185 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfiguration.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.bootstrap.autoconfigure.web; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import javax.servlet.Servlet; @@ -24,14 +25,15 @@ import javax.servlet.Servlet; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration.WebMvcConfiguration; +import org.springframework.bootstrap.context.annotation.AutoConfigureAfter; import org.springframework.bootstrap.context.annotation.ConditionalOnBean; import org.springframework.bootstrap.context.annotation.ConditionalOnClass; import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean; import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.io.ClassPathResource; @@ -56,20 +58,20 @@ import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; * {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}. * * @author Phillip Webb + * @author Dave Syer */ @Configuration -@ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) +@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, + WebMvcConfigurerAdapter.class }) @ConditionalOnMissingBean({ HandlerAdapter.class, HandlerMapping.class }) -@Import(WebMvcConfiguration.class) +@Order(Ordered.HIGHEST_PRECEDENCE + 10) +@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) public class WebMvcAutoConfiguration { - /** - * Nested configuration used because {@code @EnableWebMvc} will add HandlerAdapter and - * HandlerMapping, causing the condition to fail and the additional DispatcherServlet - * bean never to be registered if it were declared directly. - */ + // Defined as a nested config to ensure WebMvcConfigurerAdapter it not read when not + // on the classpath @EnableWebMvc - public static class WebMvcConfiguration extends WebMvcConfigurerAdapter { + public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter { @Autowired private ListableBeanFactory beanFactory; @@ -91,11 +93,6 @@ public class WebMvcAutoConfiguration { return resolver; } - @Bean - public DispatcherServlet dispatcherServlet() { - return new DispatcherServlet(); - } - @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { @@ -104,22 +101,27 @@ public class WebMvcAutoConfiguration { @Override public void addFormatters(FormatterRegistry registry) { - for (Converter converter : this.beanFactory.getBeansOfType( - Converter.class).values()) { + for (Converter converter : getBeansOfType(Converter.class)) { registry.addConverter(converter); } - for (GenericConverter converter : this.beanFactory.getBeansOfType( - GenericConverter.class).values()) { + + for (GenericConverter converter : getBeansOfType(GenericConverter.class)) { registry.addConverter(converter); } - for (Formatter formatter : this.beanFactory - .getBeansOfType(Formatter.class).values()) { + + for (Formatter formatter : getBeansOfType(Formatter.class)) { registry.addFormatter(formatter); } } + private Collection getBeansOfType(Class type) { + return this.beanFactory.getBeansOfType(type).values(); + } + @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { + // FIXME exposing the root classpath is a security risk + // eg http://localhost:8080/org/springframework/bootstrap/Banner.class registry.addResourceHandler("/resources/**").addResourceLocations("/") .addResourceLocations("classpath:/META-INF/resources/") .addResourceLocations("classpath:/resources/") @@ -130,26 +132,25 @@ public class WebMvcAutoConfiguration { .addResourceLocations("classpath:/"); } - } + @Configuration + public static class FaviconConfiguration { - @Configuration - public static class FaviconConfiguration { + @Bean + public SimpleUrlHandlerMapping faviconHandlerMapping() { + SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); + mapping.setOrder(Integer.MIN_VALUE + 1); + mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", + faviconRequestHandler())); + return mapping; + } - @Bean - public SimpleUrlHandlerMapping faviconHandlerMapping() { - SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); - mapping.setOrder(Integer.MIN_VALUE + 1); - mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", - faviconRequestHandler())); - return mapping; - } - - @Bean - protected ResourceHttpRequestHandler faviconRequestHandler() { - ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); - requestHandler.setLocations(Arrays. asList(new ClassPathResource( - "/"))); - return requestHandler; + @Bean + protected ResourceHttpRequestHandler faviconRequestHandler() { + ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); + requestHandler.setLocations(Arrays + . asList(new ClassPathResource("/"))); + return requestHandler; + } } } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonParser.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonJsonParser.java similarity index 89% rename from spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonParser.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonJsonParser.java index b9f7e43aec..2c9e0e6129 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonParser.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JacksonJsonParser.java @@ -21,12 +21,12 @@ import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; /** - * Thin wrapper for Jackson 2 {@link ObjectMapper}. + * Thin wrapper to adapt Jackson 2 {@link ObjectMapper} to {@link JsonParser}. * * @author Dave Syer - * + * @see JsonParserFactory */ -public class JacksonParser implements JsonParser { +public class JacksonJsonParser implements JsonParser { @Override public Map parseMap(String json) { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParser.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParser.java index 5dd77d7aff..ca0eace394 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParser.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParser.java @@ -19,13 +19,28 @@ import java.util.List; import java.util.Map; /** - * @author Dave Syer + * Parser that can read JSON formatted strings into {@link Map}s or {@link List}s. * + * @author Dave Syer + * @see JsonParserFactory + * @see SimpleJsonParser + * @see JacksonJsonParser + * @see YamlJsonParser */ public interface JsonParser { + /** + * Parse the specified JSON string into a Map. + * @param json the JSON to parse + * @return the parsed JSON as a map + */ Map parseMap(String json); + /** + * Parse the specified JSON string into a List. + * @param json the JSON to parse + * @return the parsed JSON as a list + */ List parseList(String json); } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParserFactory.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParserFactory.java new file mode 100644 index 0000000000..d9c7e8ad8c --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/JsonParserFactory.java @@ -0,0 +1,46 @@ +/* + * 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.bootstrap.config; + +import org.springframework.util.ClassUtils; + +/** + * Factory to create a {@link JsonParser}. + * + * @author Dave Syer + * @see JacksonJsonParser + * @see YamlJsonParser + * @see SimpleJsonParser + */ +public class JsonParserFactory { + + /** + * Static factory for the "best" JSON parser available on the classpath. Tries Jackson + * (2), then Snake YAML, and then falls back to the {@link SimpleJsonParser}. + * + * @return a {@link JsonParser} + */ + public static JsonParser getJsonParser() { + if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) { + return new JacksonJsonParser(); + } + if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { + return new YamlJsonParser(); + } + return new SimpleJsonParser(); + } +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/SimpleJsonParser.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/SimpleJsonParser.java index 54dae28eab..fcf24ab21e 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/SimpleJsonParser.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/SimpleJsonParser.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.bootstrap.config; import java.util.ArrayList; @@ -21,7 +22,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -30,29 +30,11 @@ import org.springframework.util.StringUtils; * so users will probably prefer to have a library handle things instead (Jackson or Snake * YAML are supported). * - * @see #instance() - * * @author Dave Syer - * + * @see JsonParserFactory */ public class SimpleJsonParser implements JsonParser { - /** - * Static factory for the "best" JSON parser available on the classpath. Tries Jackson - * (2), then Snake YAML, and then falls back to the {@link SimpleJsonParser}. - * - * @return a {@link JsonParser} - */ - public static JsonParser instance() { - if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { - return new YamlParser(); - } - if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) { - return new JacksonParser(); - } - return new SimpleJsonParser(); - } - @Override public Map parseMap(String json) { if (json.startsWith("{")) { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlParser.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlJsonParser.java similarity index 88% rename from spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlParser.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlJsonParser.java index 58e6740368..e8855e2723 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlParser.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/config/YamlJsonParser.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.bootstrap.config; import java.util.List; @@ -21,12 +22,12 @@ import java.util.Map; import org.yaml.snakeyaml.Yaml; /** - * Thin wrapper for Snake {@link Yaml}. + * Thin wrapper to adapt Snake {@link Yaml} to {@link JsonParser}. * * @author Dave Syer - * + * @see JsonParserFactory */ -public class YamlParser implements JsonParser { +public class YamlJsonParser implements JsonParser { @Override public Map parseMap(String json) { diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java similarity index 91% rename from spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java index 895249be3e..742d051fe8 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBean.java @@ -31,6 +31,7 @@ import org.springframework.context.annotation.Conditional; * not already contained in the {@link BeanFactory}, and throws an exception otherwise. * * @author Dave Syer + * @see ConditionalOnMissingBean */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @@ -52,4 +53,9 @@ public @interface AssertMissingBean { */ String[] name() default {}; + /** + * If the application context hierarchy (parent contexts) should be considered. + */ + boolean considerHierarchy() default true; + } diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java similarity index 81% rename from spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java rename to spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java index 978ea302a8..62b8972f27 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AssertMissingBeanCondition.java @@ -16,6 +16,8 @@ package org.springframework.bootstrap.context.annotation; +import java.util.List; + import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; @@ -35,11 +37,12 @@ class AssertMissingBeanCondition extends OnMissingBeanCondition { } @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - boolean result = super.matches(context, metadata); + protected boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata, + List beanClasses, List beanNames) throws LinkageError { + boolean result = super.matches(context, metadata, beanClasses, beanNames); if (!result) { throw new BeanCreationException("Found existing bean for classes=" - + getBeanClasses() + " and names=" + getBeanNames()); + + beanClasses + " and names=" + beanNames); } return result; } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AutoConfigurationUtils.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AutoConfigurationUtils.java deleted file mode 100644 index 92c18d90b9..0000000000 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/AutoConfigurationUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.bootstrap.context.annotation; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; - -/** - * Convenience class for storing base packages during component scan, for reference later - * (e.g. by JPA entity scanner). - * - * @author Phil Webb - * @author Dave Syer - * - */ -public abstract class AutoConfigurationUtils { - - private static String BASE_PACKAGES_BEAN = AutoConfigurationUtils.class.getName() - + ".basePackages"; - - @SuppressWarnings("unchecked") - public static List getBasePackages(BeanFactory beanFactory) { - try { - return beanFactory.getBean(BASE_PACKAGES_BEAN, List.class); - } catch (NoSuchBeanDefinitionException e) { - return Collections.emptyList(); - } - } - - public static void storeBasePackages(ConfigurableListableBeanFactory beanFactory, - List basePackages) { - if (!beanFactory.containsBean(BASE_PACKAGES_BEAN)) { - beanFactory.registerSingleton(BASE_PACKAGES_BEAN, new ArrayList( - basePackages)); - } else { - List packages = getBasePackages(beanFactory); - for (String pkg : basePackages) { - if (packages.contains(pkg)) { - packages.add(pkg); - } - } - } - } - -} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnApplicationContext.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnApplicationContext.java new file mode 100644 index 0000000000..f34eaa10bb --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnApplicationContext.java @@ -0,0 +1,51 @@ +/* + * 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.bootstrap.context.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.catalina.core.ApplicationContext; +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that only matches specific {@link ApplicationContext}s and that can + * optionally create them. + * + * @author Phillip Webb + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Conditional(OnApplicationContextCondition.class) +public @interface ConditionalOnApplicationContext { + + // FIXME complete of delete this + + /** + * The ID of the application context. + */ + String value() default ""; + + // FIXME Strategy Interface Class, eg ApplicationContextCondition + // condition=SomethingSpecific.class + + boolean createIfMissing() default false; + +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnExpression.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnExpression.java index 72fb70ce5e..a18b087094 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnExpression.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/ConditionalOnExpression.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.bootstrap.context.annotation; import java.lang.annotation.ElementType; diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableConfigurationProperties.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableConfigurationProperties.java index ac1ecd393b..e79b0000da 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableConfigurationProperties.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/EnableConfigurationProperties.java @@ -22,9 +22,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; /** + * Enable support for {@link ConfigurationProperties} annotated beans. + * {@link ConfigurationProperties} beans can be registered in the standard way (for + * example using {@link Bean @Bean} methods) or, for convenience, can be specified + * directly on this annotation. + * * @author Dave Syer */ @Target(ElementType.TYPE) @@ -33,7 +39,10 @@ import org.springframework.context.annotation.Import; @Import(EnableConfigurationPropertiesImportSelector.class) public @interface EnableConfigurationProperties { + /** + * Convenient way to quickly register {@link ConfigurationProperties} beans with + * Spring. Standard Spring Beans will also be scanned regardless of this value. + */ Class[] value() default {}; - // FIXME Javadoc } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnApplicationContextCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnApplicationContextCondition.java new file mode 100644 index 0000000000..b5252df90b --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnApplicationContextCondition.java @@ -0,0 +1,66 @@ +/* + * 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.bootstrap.context.annotation; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * @author Phillip Webb + */ +public class OnApplicationContextCondition implements Condition { + + // FIXME complete or delete + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + AnnotationAttributes attributes = AnnotationAttributes + .fromMap(metadata + .getAnnotationAttributes(ConditionalOnApplicationContext.class + .getName())); + String id = (String) attributes.get("value"); + boolean createIfMissing = attributes.getBoolean("createIfMissing"); + ApplicationContext applicationContext = context.getApplicationContext(); + + if (applicationContext != null) { + if (StringUtils.hasLength(id) && applicationContext.getId().equals(id)) { + return true; + } + } + + if (createIfMissing) { + registerCreate(applicationContext, metadata); + } + + return false; + } + + /** + * @param applicationContext + * @param metadata + */ + private void registerCreate(ApplicationContext applicationContext, + AnnotatedTypeMetadata metadata) { + Assert.notNull(applicationContext, + "Unable to create ApplicationContext from @ConditionalOnApplicationContext"); + } +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java index 7eb22f87a4..4ea8fa40d8 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/annotation/OnMissingClassCondition.java @@ -78,4 +78,5 @@ class OnMissingClassCondition implements Condition { } } + // FIXME merge with OnClassCondition } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizer.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizer.java index 2d3c8fe0c6..c8f554d03d 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizer.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizer.java @@ -25,6 +25,7 @@ package org.springframework.bootstrap.context.embedded; * than injecting them with @Autowired. * * @author Dave Syer + * @see EmbeddedServletContainerCustomizerBeanPostProcessor */ public interface EmbeddedServletContainerCustomizer { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizerBeanPostProcessor.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizerBeanPostProcessor.java new file mode 100644 index 0000000000..7014ff74c4 --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedServletContainerCustomizerBeanPostProcessor.java @@ -0,0 +1,86 @@ +/* + * 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.bootstrap.context.embedded; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; + +/** + * {@link BeanPostProcessor} that apply all {@link EmbeddedServletContainerCustomizer}s + * from the bean factory to {@link ConfigurableEmbeddedServletContainerFactory} beans. + * + * @author Dave Syer + * @author Phillip Webb + */ +public class EmbeddedServletContainerCustomizerBeanPostProcessor implements + BeanPostProcessor, ApplicationContextAware { + + // FIXME should we register this by default, Javadoc in + // EmbeddedServletContainerCustomizer suggests so + + private ApplicationContext applicationContext; + + private List customizers; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof ConfigurableEmbeddedServletContainerFactory) { + postProcessBeforeInitialization((ConfigurableEmbeddedServletContainerFactory) bean); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + private void postProcessBeforeInitialization( + ConfigurableEmbeddedServletContainerFactory bean) { + for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) { + customizer.customize(bean); + } + } + + private Collection getCustomizers() { + if (this.customizers == null) { + // Look up does not include the parent context + this.customizers = new ArrayList( + this.applicationContext.getBeansOfType( + EmbeddedServletContainerCustomizer.class).values()); + Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE); + this.customizers = Collections.unmodifiableList(this.customizers); + } + return this.customizers; + } + +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedWebApplicationContext.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedWebApplicationContext.java index 98a73b10c7..c7c0d65660 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedWebApplicationContext.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/embedded/EmbeddedWebApplicationContext.java @@ -34,13 +34,12 @@ import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; import org.springframework.web.context.ContextLoader; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.ServletContextAware; @@ -153,17 +152,22 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext * @return a {@link EmbeddedServletContainerFactory} (never {@code null}) */ protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() { - try { - return getBeanFactory().getBean(EmbeddedServletContainerFactory.class); - } catch (NoUniqueBeanDefinitionException ex) { - throw new ApplicationContextException( - "Unable to start EmbeddedWebApplicationContext due to multiple " - + "EmbeddedServletContainerFactory beans.", ex); - } catch (NoSuchBeanDefinitionException ex) { + // Use bean names so that we don't consider the hierarchy + String[] beanNames = getBeanFactory().getBeanNamesForType( + EmbeddedServletContainerFactory.class); + if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start EmbeddedWebApplicationContext due to missing " - + "EmbeddedServletContainerFactory bean.", ex); + + "EmbeddedServletContainerFactory bean."); } + if (beanNames.length > 1) { + throw new ApplicationContextException( + "Unable to start EmbeddedWebApplicationContext due to multiple " + + "EmbeddedServletContainerFactory beans : " + + StringUtils.arrayToCommaDelimitedString(beanNames)); + } + return getBeanFactory().getBean(beanNames[0], + EmbeddedServletContainerFactory.class); } /** diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/ContextIdApplicationContextInitializer.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/ContextIdApplicationContextInitializer.java index 7033e7a461..450e56e1c6 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/ContextIdApplicationContextInitializer.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/ContextIdApplicationContextInitializer.java @@ -16,6 +16,7 @@ package org.springframework.bootstrap.context.initializer; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; @@ -23,6 +24,25 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.StringUtils; /** + * {@link ApplicationContextInitializer} that set the Spring + * {@link ApplicationContext#getId() ApplicationContext ID}. The following environment + * properties will be consulted to create the ID: + *
    + *
  • spring.application.name
  • + *
  • vcap.application.name
  • + *
  • spring.config.name
  • + *
+ * If no property is set the ID 'application' will be used. + * + *

+ * In addition the following environment properties will be consulted to append a relevant + * port or index: + * + *

    + *
  • spring.application.index
  • + *
  • vcap.application.instance_index
  • + *
  • PORT
  • + *
* * @author Dave Syer */ @@ -58,6 +78,7 @@ public class ContextIdApplicationContextInitializer implements if (index >= 0) { name = name + ":" + index; } else { + // FIXME do we want this String profiles = StringUtils.arrayToCommaDelimitedString(environment .getActiveProfiles()); if (StringUtils.hasText(profiles)) { diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/VcapApplicationContextInitializer.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/VcapApplicationContextInitializer.java index 9c667d1ba0..33f6d7ac3e 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/VcapApplicationContextInitializer.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/context/initializer/VcapApplicationContextInitializer.java @@ -24,7 +24,7 @@ import java.util.Map.Entry; import java.util.Properties; import org.springframework.bootstrap.config.JsonParser; -import org.springframework.bootstrap.config.SimpleJsonParser; +import org.springframework.bootstrap.config.JsonParserFactory; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; @@ -89,7 +89,7 @@ public class VcapApplicationContextInitializer implements private int order = Integer.MIN_VALUE + 11; - private JsonParser parser = SimpleJsonParser.instance(); + private JsonParser parser = JsonParserFactory.getJsonParser(); public void setOrder(int order) { this.order = order; diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/maven/PropertiesMergingResourceTransformer.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/maven/PropertiesMergingResourceTransformer.java index 7369cb9d98..28fc21660b 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/maven/PropertiesMergingResourceTransformer.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/maven/PropertiesMergingResourceTransformer.java @@ -35,6 +35,8 @@ import org.apache.maven.plugins.shade.resource.ResourceTransformer; */ public class PropertiesMergingResourceTransformer implements ResourceTransformer { + // FIXME move out of core + String resource; // Set this in pom configuration with ... private Properties data = new Properties(); diff --git a/spring-bootstrap/src/main/resources/META-INF/spring.factories b/spring-bootstrap/src/main/resources/META-INF/spring.factories index 01f0bf0b16..4381606018 100644 --- a/spring-bootstrap/src/main/resources/META-INF/spring.factories +++ b/spring-bootstrap/src/main/resources/META-INF/spring.factories @@ -1,18 +1,21 @@ +# Auto Configure org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\ -org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.MessageSourceAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.jdbc.DataSourceAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.jdbc.DataSourceAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ -org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerConfiguration,\ -org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration,\ +org.springframework.bootstrap.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ +org.springframework.bootstrap.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration + +# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.bootstrap.context.initializer.ConfigFileApplicationContextInitializer,\ -org.springframework.bootstrap.context.initializer.LoggingApplicationContextInitializer,\ -org.springframework.bootstrap.context.initializer.VcapApplicationContextInitializer,\ org.springframework.bootstrap.context.initializer.ContextIdApplicationContextInitializer,\ -org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer \ No newline at end of file +org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer,\ +org.springframework.bootstrap.context.initializer.LoggingApplicationContextInitializer,\ +org.springframework.bootstrap.context.initializer.VcapApplicationContextInitializer diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java index e0e5d5a555..ba13c10948 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/data/JpaRepositoriesAutoConfigurationTests.java @@ -24,6 +24,7 @@ import org.springframework.bootstrap.autoconfigure.data.test.City; import org.springframework.bootstrap.autoconfigure.data.test.CityRepository; import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration; import org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.bootstrap.context.annotation.ComponentScanDetectorConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -42,6 +43,7 @@ public class JpaRepositoriesAutoConfigurationTests { public void testDefaultRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration.class, + ComponentScanDetectorConfiguration.class, EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index e696f7f326..18577f7aa9 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -23,6 +23,7 @@ import org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfig import org.springframework.bootstrap.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration; import org.springframework.bootstrap.autoconfigure.orm.jpa.test.City; +import org.springframework.bootstrap.context.annotation.ComponentScanDetectorConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.orm.jpa.JpaTransactionManager; @@ -39,8 +40,8 @@ public class HibernateJpaAutoConfigurationTests { @Test public void testEntityManagerCreated() throws Exception { - this.context.register(EmbeddedDatabaseConfiguration.class, - HibernateJpaAutoConfiguration.class, + this.context.register(ComponentScanDetectorConfiguration.class, + EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class); this.context.refresh(); assertNotNull(this.context.getBean(DataSource.class)); @@ -49,8 +50,8 @@ public class HibernateJpaAutoConfigurationTests { @Test public void testDataSourceTransactionManagerNotCreated() throws Exception { - this.context.register(EmbeddedDatabaseConfiguration.class, - HibernateJpaAutoConfiguration.class, + this.context.register(ComponentScanDetectorConfiguration.class, + EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class); this.context.refresh(); diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java new file mode 100644 index 0000000000..362a8fd81a --- /dev/null +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java @@ -0,0 +1,125 @@ +/* + * 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.bootstrap.autoconfigure.web; + +import javax.servlet.Servlet; + +import org.junit.Test; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.bootstrap.context.annotation.ConditionalOnExpression; +import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; +import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; +import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.bootstrap.context.embedded.MockEmbeddedServletContainerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link EmbeddedServletContainerAutoConfiguration}. + * + * @author Dave Syer + */ +public class EmbeddedServletContainerAutoConfigurationTests { + + private AnnotationConfigEmbeddedWebApplicationContext context; + + @Test + public void createFromConfigClass() throws Exception { + this.context = new AnnotationConfigEmbeddedWebApplicationContext( + EmbeddedContainerConfiguration.class, + EmbeddedServletContainerAutoConfiguration.class); + verifyContext(); + } + + @Test + public void containerHasNoServletContext() throws Exception { + this.context = new AnnotationConfigEmbeddedWebApplicationContext( + EmbeddedContainerConfiguration.class, + EnsureContainerHasNoServletContext.class, + EmbeddedServletContainerAutoConfiguration.class); + verifyContext(); + } + + @Test + public void customizeContainerThroughCallback() throws Exception { + this.context = new AnnotationConfigEmbeddedWebApplicationContext( + EmbeddedContainerConfiguration.class, + CallbackEmbeddedContainerCustomizer.class, + EmbeddedServletContainerAutoConfiguration.class); + verifyContext(); + assertEquals(9000, getContainerFactory().getPort()); + } + + private void verifyContext() { + MockEmbeddedServletContainerFactory containerFactory = getContainerFactory(); + Servlet servlet = this.context.getBean(Servlet.class); + verify(containerFactory.getServletContext()).addServlet("dispatcherServlet", + servlet); + } + + private MockEmbeddedServletContainerFactory getContainerFactory() { + return this.context.getBean(MockEmbeddedServletContainerFactory.class); + } + + @Configuration + @ConditionalOnExpression("true") + public static class EmbeddedContainerConfiguration { + + @Bean + public EmbeddedServletContainerFactory containerFactory() { + return new MockEmbeddedServletContainerFactory(); + } + + } + + @Component + public static class EnsureContainerHasNoServletContext implements BeanPostProcessor { + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof ConfigurableEmbeddedServletContainerFactory) { + MockEmbeddedServletContainerFactory containerFactory = (MockEmbeddedServletContainerFactory) bean; + assertNull(containerFactory.getServletContext()); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) { + return bean; + } + + } + + @Component + public static class CallbackEmbeddedContainerCustomizer implements + EmbeddedServletContainerCustomizer { + @Override + public void customize(ConfigurableEmbeddedServletContainerFactory factory) { + factory.setPort(9000); + } + } + +} diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfigurationTests.java index 1a6b850465..ec089dc2c7 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfigurationTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/ServerPropertiesConfigurationTests.java @@ -26,6 +26,7 @@ import org.springframework.bootstrap.TestUtils; import org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; +import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory; import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.bootstrap.properties.ServerProperties; @@ -36,6 +37,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; /** + * Tests for {@link ServerPropertiesAutoConfiguration}. + * * @author Dave Syer */ public class ServerPropertiesConfigurationTests { @@ -60,9 +63,7 @@ public class ServerPropertiesConfigurationTests { @Test public void createFromConfigClass() throws Exception { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - this.context.register(EmbeddedContainerConfiguration.class, - EmbeddedContainerCustomizerConfiguration.class, - ServerPropertiesConfiguration.class, + this.context.register(Config.class, ServerPropertiesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); TestUtils.addEnviroment(this.context, "server.port:9000"); this.context.refresh(); @@ -76,9 +77,7 @@ public class ServerPropertiesConfigurationTests { public void tomcatProperties() throws Exception { containerFactory = Mockito.mock(TomcatEmbeddedServletContainerFactory.class); this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - this.context.register(EmbeddedContainerCustomizerConfiguration.class, - EmbeddedContainerConfiguration.class, - ServerPropertiesConfiguration.class, + this.context.register(Config.class, ServerPropertiesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); TestUtils.addEnviroment(this.context, "server.tomcat.basedir:target/foo"); this.context.refresh(); @@ -89,13 +88,18 @@ public class ServerPropertiesConfigurationTests { } @Configuration - protected static class EmbeddedContainerConfiguration { + protected static class Config { @Bean public EmbeddedServletContainerFactory containerFactory() { return ServerPropertiesConfigurationTests.containerFactory; } + @Bean + public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContainerCustomizerBeanPostProcessor() { + return new EmbeddedServletContainerCustomizerBeanPostProcessor(); + } + } } diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfigurationTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfigurationTests.java index 4919495896..5829e32c1e 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfigurationTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/autoconfigure/web/WebMvcAutoConfigurationTests.java @@ -13,109 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.bootstrap.autoconfigure.web; -import javax.servlet.Servlet; - -import org.junit.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.bootstrap.context.annotation.ConditionalOnExpression; -import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; -import org.springframework.bootstrap.context.embedded.ConfigurableEmbeddedServletContainerFactory; -import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerCustomizer; -import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory; -import org.springframework.bootstrap.context.embedded.MockEmbeddedServletContainerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.verify; +import org.junit.Ignore; /** - * @author Dave Syer + * Tests for {@link WebMvcAutoConfiguration}. + * + * @author Phillip Webb */ +@Ignore public class WebMvcAutoConfigurationTests { - - private AnnotationConfigEmbeddedWebApplicationContext context; - - @Test - public void createFromConfigClass() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext( - WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class); - verifyContext(); - } - - @Test - public void containerHasNoServletContext() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext( - WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class, - EnsureContainerHasNoServletContext.class); - verifyContext(); - } - - @Test - public void customizeContainerThroughCallback() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext( - WebMvcAutoConfiguration.class, EmbeddedContainerConfiguration.class, - EmbeddedContainerCustomizerConfiguration.class, - CallbackEmbeddedContainerCustomizer.class); - verifyContext(); - assertEquals(9000, getContainerFactory().getPort()); - } - - private void verifyContext() { - MockEmbeddedServletContainerFactory containerFactory = getContainerFactory(); - Servlet servlet = this.context.getBean(Servlet.class); - verify(containerFactory.getServletContext()).addServlet("dispatcherServlet", - servlet); - } - - private MockEmbeddedServletContainerFactory getContainerFactory() { - return this.context.getBean(MockEmbeddedServletContainerFactory.class); - } - - @Configuration - @ConditionalOnExpression("true") - public static class EmbeddedContainerConfiguration { - - @Bean - public EmbeddedServletContainerFactory containerFactory() { - return new MockEmbeddedServletContainerFactory(); - } - - } - - @Component - public static class EnsureContainerHasNoServletContext implements BeanPostProcessor { - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof ConfigurableEmbeddedServletContainerFactory) { - MockEmbeddedServletContainerFactory containerFactory = (MockEmbeddedServletContainerFactory) bean; - assertNull(containerFactory.getServletContext()); - } - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) { - return bean; - } - - } - - @Component - public static class CallbackEmbeddedContainerCustomizer implements - EmbeddedServletContainerCustomizer { - @Override - public void customize(ConfigurableEmbeddedServletContainerFactory factory) { - factory.setPort(9000); - } - } + // FIXME } diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/JacksonParserTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/JacksonParserTests.java index 9b43f72122..873f60e7dc 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/JacksonParserTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/JacksonParserTests.java @@ -23,6 +23,6 @@ public class JacksonParserTests extends SimpleJsonParserTests { @Override protected JsonParser getParser() { - return new JacksonParser(); + return new JacksonJsonParser(); } } diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/YamlParserTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/YamlParserTests.java index e6a321b7a1..1029a1ab4b 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/YamlParserTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/config/YamlParserTests.java @@ -23,6 +23,6 @@ public class YamlParserTests extends SimpleJsonParserTests { @Override protected JsonParser getParser() { - return new YamlParser(); + return new YamlJsonParser(); } } diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/EnableConfigurationPropertiesTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/EnableConfigurationPropertiesTests.java index ebc395054c..c8508d579e 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/EnableConfigurationPropertiesTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/EnableConfigurationPropertiesTests.java @@ -98,7 +98,7 @@ public class EnableConfigurationPropertiesTests { // definition created with a direct regsistration (as opposed to a @Bean) @Test(expected = BeanCreationException.class) public void testPropertiesBindingWithDefaults() { - this.context.register(DefaultConfiguration.class, TestConfiguration.class); + this.context.register(TestConfiguration.class, DefaultConfiguration.class); this.context.refresh(); String[] beanNames = this.context.getBeanNamesForType(TestProperties.class); assertEquals("Wrong beans: " + Arrays.asList(beanNames), 1, beanNames.length); diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/OnApplicationContextConditionTest.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/OnApplicationContextConditionTest.java new file mode 100644 index 0000000000..dc9829d290 --- /dev/null +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/annotation/OnApplicationContextConditionTest.java @@ -0,0 +1,124 @@ +/* + * 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.bootstrap.context.annotation; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.util.ObjectUtils; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link OnApplicationContextCondition}. + * + * @author Phillip Webb + */ +@SuppressWarnings("resource") +public class OnApplicationContextConditionTest { + + @Test + public void forContextById() throws Exception { + AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); + parent.setId("parent"); + parent.register(ForContextByIdConf.class); + + AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext(); + child.setId("child"); + child.setParent(parent); + child.register(ForContextByIdConf.class); + + parent.refresh(); + child.refresh(); + + assertThat(parent.containsLocalBean("inParent"), equalTo(true)); + assertThat(parent.containsLocalBean("inChild"), equalTo(false)); + + assertThat(child.containsLocalBean("inParent"), equalTo(false)); + assertThat(child.containsLocalBean("inChild"), equalTo(true)); + } + + @Test + @Ignore + public void createContext() throws Exception { + AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); + ApplicationContextCollector collector = new ApplicationContextCollector(); + parent.addApplicationListener(collector); + parent.register(CreateContext.class); + parent.refresh(); + assertThat(collector.get("child").containsLocalBean("inChild"), equalTo(true)); + } + + // FIXME + // createContextOnBeanMethod + // createContextComponent + + private static class ApplicationContextCollector implements + ApplicationListener { + + private Set contexts = new HashSet(); + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + this.contexts.add(event.getApplicationContext()); + } + + public ApplicationContext get(String id) { + for (ApplicationContext context : this.contexts) { + if (ObjectUtils.nullSafeEquals(context.getId(), id)) { + return context; + } + } + throw new IllegalArgumentException("No such ID " + id); + } + } + + @Configuration + public static class ForContextByIdConf { + + @Bean + @ConditionalOnApplicationContext("parent") + public String inParent() { + return "inParent"; + } + + @Bean + @ConditionalOnApplicationContext("child") + public String inChild() { + return "inChild"; + } + } + + @Configuration + @ConditionalOnApplicationContext(value = "child", createIfMissing = true) + public static class CreateContext { + + @Bean + public String inChild() { + return "inChild"; + } + } + +} diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/embedded/AnnotationConfigEmbeddedWebApplicationContextTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/embedded/AnnotationConfigEmbeddedWebApplicationContextTests.java index 4921536be3..2cc5f23627 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/embedded/AnnotationConfigEmbeddedWebApplicationContextTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/embedded/AnnotationConfigEmbeddedWebApplicationContextTests.java @@ -86,7 +86,8 @@ public class AnnotationConfigEmbeddedWebApplicationContextTests { AnnotationConfigEmbeddedWebApplicationContext parent = new AnnotationConfigEmbeddedWebApplicationContext( EmbeddedContainerConfiguration.class); this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - this.context.register(ServletContextAwareConfiguration.class); + this.context.register(EmbeddedContainerConfiguration.class, + ServletContextAwareConfiguration.class); this.context.setParent(parent); this.context.refresh(); verifyContext(); diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/test/EnableConfigurationPropertiesTests.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/test/EnableConfigurationPropertiesTests.java index 6911dbbe4f..15fd3d7441 100644 --- a/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/test/EnableConfigurationPropertiesTests.java +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/context/test/EnableConfigurationPropertiesTests.java @@ -33,6 +33,8 @@ import org.springframework.core.io.support.PropertiesLoaderUtils; import static org.junit.Assert.assertEquals; /** + * Tests for {@link EnableConfigurationProperties}. + * * @author Dave Syer */ public class EnableConfigurationPropertiesTests { @@ -105,6 +107,7 @@ public class EnableConfigurationPropertiesTests { @ConfigurationProperties(name = "external") public static class External { + private String name; public String getName() { @@ -118,6 +121,7 @@ public class EnableConfigurationPropertiesTests { @ConfigurationProperties(name = "another") public static class Another { + private String name; public String getName() {