Polish and Fixup

Polish and fixup:
- Ordered auto-configuration
- @ConditionalOnBean default on @Bean methods
- Improved separation of auto-configure classes
- Consistent naming
- Javadoc, code formatting and tests
This commit is contained in:
Phillip Webb 2013-06-12 12:33:19 -07:00
parent 2f84df66b6
commit dd69d0f660
42 changed files with 749 additions and 391 deletions

View File

@ -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}")

View File

@ -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();

View File

@ -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;

View File

@ -206,7 +206,6 @@ public class DataSourceAutoConfiguration {
}
return super.matches(context, metadata);
}
}
static abstract class NonEmbeddedDatabaseCondition implements Condition {

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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<EmbeddedServletContainerCustomizer> customizers = beanFactory
.getBeansOfType(EmbeddedServletContainerCustomizer.class).values();
return new EmbeddedContainerCustomizerBeanPostProcessor(customizers);
}
private static final class EmbeddedContainerCustomizerBeanPostProcessor implements
BeanPostProcessor {
private List<EmbeddedServletContainerCustomizer> customizers;
public EmbeddedContainerCustomizerBeanPostProcessor(
Collection<EmbeddedServletContainerCustomizer> customizers) {
final List<EmbeddedServletContainerCustomizer> list = new ArrayList<EmbeddedServletContainerCustomizer>(
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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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());

View File

@ -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 <T> Collection<T> getBeansOfType(Class<T> 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.<Resource> asList(new ClassPathResource(
"/")));
return requestHandler;
@Bean
protected ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler.setLocations(Arrays
.<Resource> asList(new ClassPathResource("/")));
return requestHandler;
}
}
}

View File

@ -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<String, Object> parseMap(String json) {

View File

@ -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<String, Object> 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<Object> parseList(String json);
}

View File

@ -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();
}
}

View File

@ -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<String, Object> parseMap(String json) {
if (json.startsWith("{")) {

View File

@ -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<String, Object> parseMap(String json) {

View File

@ -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;
}

View File

@ -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<String> beanClasses, List<String> 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;
}

View File

@ -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<String> 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<String> basePackages) {
if (!beanFactory.containsBean(BASE_PACKAGES_BEAN)) {
beanFactory.registerSingleton(BASE_PACKAGES_BEAN, new ArrayList<String>(
basePackages));
} else {
List<String> packages = getBasePackages(beanFactory);
for (String pkg : basePackages) {
if (packages.contains(pkg)) {
packages.add(pkg);
}
}
}
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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
}

View File

@ -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");
}
}

View File

@ -78,4 +78,5 @@ class OnMissingClassCondition implements Condition {
}
}
// FIXME merge with OnClassCondition
}

View File

@ -25,6 +25,7 @@ package org.springframework.bootstrap.context.embedded;
* than injecting them with <code>@Autowired</code>.
*
* @author Dave Syer
* @see EmbeddedServletContainerCustomizerBeanPostProcessor
*/
public interface EmbeddedServletContainerCustomizer {

View File

@ -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<EmbeddedServletContainerCustomizer> 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<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.applicationContext.getBeansOfType(
EmbeddedServletContainerCustomizer.class).values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
}

View File

@ -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);
}
/**

View File

@ -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:
* <ul>
* <li>spring.application.name</li>
* <li>vcap.application.name</li>
* <li>spring.config.name</li>
* </ul>
* If no property is set the ID 'application' will be used.
*
* <p>
* In addition the following environment properties will be consulted to append a relevant
* port or index:
*
* <ul>
* <li>spring.application.index</li>
* <li>vcap.application.instance_index</li>
* <li>PORT</li>
* </ul>
*
* @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)) {

View File

@ -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;

View File

@ -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 <resource>...</resource>
private Properties data = new Properties();

View File

@ -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
org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer,\
org.springframework.bootstrap.context.initializer.LoggingApplicationContextInitializer,\
org.springframework.bootstrap.context.initializer.VcapApplicationContextInitializer

View File

@ -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);

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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
}

View File

@ -23,6 +23,6 @@ public class JacksonParserTests extends SimpleJsonParserTests {
@Override
protected JsonParser getParser() {
return new JacksonParser();
return new JacksonJsonParser();
}
}

View File

@ -23,6 +23,6 @@ public class YamlParserTests extends SimpleJsonParserTests {
@Override
protected JsonParser getParser() {
return new YamlParser();
return new YamlJsonParser();
}
}

View File

@ -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);

View File

@ -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<ContextRefreshedEvent> {
private Set<ApplicationContext> contexts = new HashSet<ApplicationContext>();
@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";
}
}
}

View File

@ -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();

View File

@ -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() {