[bs-175] Generic dispatcher features for SpringApplication
* Move Spring.main into SpringApplication.main * User can bind command line or application.properties into SpringApplication * User can provide sources dynamically with --spring.main.sources (a CSV list of class names, package names or XML resource locations) * One side effect was to make DocumentMatchers stateless [#52830829]
This commit is contained in:
parent
d75c1e4956
commit
4ce6b64dce
|
@ -1,98 +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.autoconfigure.main;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.autoconfigure.EnableAutoConfiguration;
|
|
||||||
import org.springframework.bootstrap.SpringApplication;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.SpringVersion;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Very simple main class that can be used to launch an application from sources (class,
|
|
||||||
* package or XML). Useful for demos and testing, perhaps less for production use (where
|
|
||||||
* the {@link SpringApplication} run methods are often more convenient).
|
|
||||||
*
|
|
||||||
* @author Dave Syer
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableAutoConfiguration
|
|
||||||
@ComponentScan
|
|
||||||
public abstract class Spring {
|
|
||||||
|
|
||||||
// FIXME can we delete this? is it used? does it belong here
|
|
||||||
|
|
||||||
private static ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
|
|
||||||
true);
|
|
||||||
|
|
||||||
private static ApplicationContext context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the context if there is one
|
|
||||||
*/
|
|
||||||
public static ApplicationContext getApplicationContext() {
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic main that can be used to launch an application.
|
|
||||||
*
|
|
||||||
* @param args command line arguments
|
|
||||||
* @see SpringApplication#run(Object[], String[])
|
|
||||||
* @see SpringApplication#run(Object, String...)
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
|
|
||||||
List<String> strings = new ArrayList<String>();
|
|
||||||
List<Object> sources = new ArrayList<Object>();
|
|
||||||
|
|
||||||
for (String arg : args) {
|
|
||||||
if (ClassUtils.isPresent(arg, null)) {
|
|
||||||
sources.add(ClassUtils.forName(arg, null));
|
|
||||||
}
|
|
||||||
else if (arg.endsWith(".xml")) {
|
|
||||||
sources.add(arg);
|
|
||||||
}
|
|
||||||
else if (!scanner.findCandidateComponents(arg).isEmpty()) {
|
|
||||||
sources.add(arg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strings.add(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sources.isEmpty()) {
|
|
||||||
sources.add(Spring.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
context = SpringApplication.run(sources.toArray(new Object[sources.size()]),
|
|
||||||
strings.toArray(new String[strings.size()]));
|
|
||||||
|
|
||||||
LogFactory.getLog(Spring.class).info(
|
|
||||||
"Running Spring " + SpringVersion.getVersion() + " with sources: "
|
|
||||||
+ sources);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,7 +20,7 @@ import org.junit.Ignore;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
import org.junit.runners.Suite.SuiteClasses;
|
import org.junit.runners.Suite.SuiteClasses;
|
||||||
import org.springframework.autoconfigure.main.SimpleMainTests;
|
import org.springframework.bootstrap.SimpleMainTests;
|
||||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactoryTests;
|
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactoryTests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,66 +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.autoconfigure.main;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.springframework.autoconfigure.main.Spring;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link Spring}.
|
|
||||||
*
|
|
||||||
* @author Dave Syer
|
|
||||||
*/
|
|
||||||
public class SimpleMainTests {
|
|
||||||
|
|
||||||
private ApplicationContext context;
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void close() {
|
|
||||||
if (this.context instanceof ConfigurableApplicationContext) {
|
|
||||||
((ConfigurableApplicationContext) this.context).close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void emptyApplicationContext() throws Exception {
|
|
||||||
Spring.main(new String[0]);
|
|
||||||
this.context = Spring.getApplicationContext();
|
|
||||||
assertNotNull(this.context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void basePackageScan() throws Exception {
|
|
||||||
Spring.main(new String[] { ClassUtils.getPackageName(Spring.class) });
|
|
||||||
this.context = Spring.getApplicationContext();
|
|
||||||
assertNotNull(this.context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void xmlContext() throws Exception {
|
|
||||||
Spring.main(new String[] { Spring.class.getName(),
|
|
||||||
"org/springframework/bootstrap/sample-beans.xml" });
|
|
||||||
this.context = Spring.getApplicationContext();
|
|
||||||
assertNotNull(this.context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -29,10 +29,14 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
|
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
|
||||||
import org.springframework.core.type.filter.TypeFilter;
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a
|
* Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a
|
||||||
|
@ -162,13 +166,37 @@ class BeanDefinitionLoader {
|
||||||
if (loadedResource != null && loadedResource.exists()) {
|
if (loadedResource != null && loadedResource.exists()) {
|
||||||
return load(loadedResource);
|
return load(loadedResource);
|
||||||
}
|
}
|
||||||
Package packageResource = Package.getPackage(source.toString());
|
Package packageResource = findPackage(source);
|
||||||
if (packageResource != null) {
|
if (packageResource != null) {
|
||||||
return load(packageResource);
|
return load(packageResource);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Invalid source '" + source + "'");
|
throw new IllegalArgumentException("Invalid source '" + source + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Package findPackage(CharSequence source) {
|
||||||
|
Package pkg = Package.getPackage(source.toString());
|
||||||
|
if (pkg != null) {
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Attempt to find a class in this package
|
||||||
|
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
|
||||||
|
getClass().getClassLoader());
|
||||||
|
Resource[] resources = resolver.getResources(ClassUtils
|
||||||
|
.convertClassNameToResourcePath(source.toString()) + "/*.class");
|
||||||
|
for (Resource resource : resources) {
|
||||||
|
String className = StringUtils.stripFilenameExtension(resource
|
||||||
|
.getFilename());
|
||||||
|
load(Class.forName(source.toString() + "." + className));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// swallow exception and continue
|
||||||
|
}
|
||||||
|
return Package.getPackage(source.toString());
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isComponent(Class<?> type) {
|
private boolean isComponent(Class<?> type) {
|
||||||
// This has to be a bit of a guess. The only way to be sure that this type is
|
// This has to be a bit of a guess. The only way to be sure that this type is
|
||||||
// eligible is to make a bean definition out of it and try to instantiate it.
|
// eligible is to make a bean definition out of it and try to instantiate it.
|
||||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.bootstrap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -36,20 +36,19 @@ import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.support.AbstractApplicationContext;
|
import org.springframework.context.support.AbstractApplicationContext;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
import org.springframework.core.env.CommandLinePropertySource;
|
import org.springframework.core.env.CommandLinePropertySource;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.core.env.MapPropertySource;
|
|
||||||
import org.springframework.core.env.PropertySource;
|
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,7 +132,7 @@ public class SpringApplication {
|
||||||
|
|
||||||
private final Log log = LogFactory.getLog(getClass());
|
private final Log log = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private Object[] sources;
|
private Set<Object> sources = new LinkedHashSet<Object>();
|
||||||
|
|
||||||
private Class<?> mainApplicationClass;
|
private Class<?> mainApplicationClass;
|
||||||
|
|
||||||
|
@ -169,8 +168,7 @@ public class SpringApplication {
|
||||||
* @see #SpringApplication(ResourceLoader, Object...)
|
* @see #SpringApplication(ResourceLoader, Object...)
|
||||||
*/
|
*/
|
||||||
public SpringApplication(Object... sources) {
|
public SpringApplication(Object... sources) {
|
||||||
Assert.notEmpty(sources, "Sources must not be empty");
|
addSources(sources);
|
||||||
this.sources = sources;
|
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,12 +183,20 @@ public class SpringApplication {
|
||||||
* @see #SpringApplication(ResourceLoader, Object...)
|
* @see #SpringApplication(ResourceLoader, Object...)
|
||||||
*/
|
*/
|
||||||
public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
|
public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
|
||||||
Assert.notEmpty(sources, "Sources must not be empty");
|
|
||||||
this.resourceLoader = resourceLoader;
|
this.resourceLoader = resourceLoader;
|
||||||
this.sources = sources;
|
addSources(sources);
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addSources(Object[] sources) {
|
||||||
|
if (sources == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Object source : sources) {
|
||||||
|
this.sources.add(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
this.webEnvironment = deduceWebEnvironment();
|
this.webEnvironment = deduceWebEnvironment();
|
||||||
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
|
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
|
||||||
|
@ -228,6 +234,22 @@ public class SpringApplication {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic main that can be used to launch an application.
|
||||||
|
*
|
||||||
|
* @param args command line arguments
|
||||||
|
* @see SpringApplication#run(Object[], String[])
|
||||||
|
* @see SpringApplication#run(Object, String...)
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SpringApplication.run(new Object[0], args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class EmptyConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the Spring application, creating and refreshing a new
|
* Run the Spring application, creating and refreshing a new
|
||||||
* {@link ApplicationContext}.
|
* {@link ApplicationContext}.
|
||||||
|
@ -235,29 +257,30 @@ public class SpringApplication {
|
||||||
* @return a running {@link ApplicationContext}
|
* @return a running {@link ApplicationContext}
|
||||||
*/
|
*/
|
||||||
public ApplicationContext run(String... args) {
|
public ApplicationContext run(String... args) {
|
||||||
applySpringApplicationInitializers();
|
applySpringApplicationInitializers(args);
|
||||||
|
Assert.notEmpty(this.sources, "Sources must not be empty");
|
||||||
if (this.showBanner) {
|
if (this.showBanner) {
|
||||||
printBanner();
|
printBanner();
|
||||||
}
|
}
|
||||||
ApplicationContext context = createApplicationContext();
|
ApplicationContext context = createApplicationContext();
|
||||||
postProcessApplicationContext(context);
|
postProcessApplicationContext(context);
|
||||||
addPropertySources(context, args);
|
|
||||||
if (context instanceof ConfigurableApplicationContext) {
|
if (context instanceof ConfigurableApplicationContext) {
|
||||||
applyInitializers((ConfigurableApplicationContext) context);
|
applyInitializers((ConfigurableApplicationContext) context);
|
||||||
}
|
}
|
||||||
if (this.logStartupInfo) {
|
if (this.logStartupInfo) {
|
||||||
logStartupInfo();
|
logStartupInfo();
|
||||||
}
|
}
|
||||||
load(context, this.sources);
|
load(context, this.sources.toArray(new Object[this.sources.size()]));
|
||||||
refresh(context);
|
refresh(context);
|
||||||
runCommandLineRunners(context, args);
|
runCommandLineRunners(context, args);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySpringApplicationInitializers() {
|
private void applySpringApplicationInitializers(String[] args) {
|
||||||
|
args = StringUtils.mergeStringArrays(this.defaultCommandLineArgs, args);
|
||||||
for (ApplicationContextInitializer<?> initializer : this.initializers) {
|
for (ApplicationContextInitializer<?> initializer : this.initializers) {
|
||||||
if (initializer instanceof SpringApplicationInitializer) {
|
if (initializer instanceof SpringApplicationInitializer) {
|
||||||
((SpringApplicationInitializer) initializer).initialize(this);
|
((SpringApplicationInitializer) initializer).initialize(this, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,6 +312,7 @@ public class SpringApplication {
|
||||||
|
|
||||||
protected void logStartupInfo() {
|
protected void logStartupInfo() {
|
||||||
new StartupInfoLogger(this.mainApplicationClass).log(getApplicationLog());
|
new StartupInfoLogger(this.mainApplicationClass).log(getApplicationLog());
|
||||||
|
getApplicationLog().info("Sources: " + this.sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,88 +382,6 @@ public class SpringApplication {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add any {@link PropertySource}s to the application context environment.
|
|
||||||
* @param context the application context
|
|
||||||
* @param args run arguments
|
|
||||||
*/
|
|
||||||
protected void addPropertySources(ApplicationContext context, String[] args) {
|
|
||||||
Environment environment = context.getEnvironment();
|
|
||||||
if (environment instanceof ConfigurableEnvironment) {
|
|
||||||
ConfigurableEnvironment configurable = (ConfigurableEnvironment) environment;
|
|
||||||
if (this.addCommandLineProperties) {
|
|
||||||
// Don't use SimpleCommandLinePropertySource (SPR-10579)
|
|
||||||
PropertySource<?> propertySource = new MapPropertySource(
|
|
||||||
"commandLineArgs", mergeCommandLineArgs(
|
|
||||||
this.defaultCommandLineArgs, args));
|
|
||||||
configurable.getPropertySources().addFirst(propertySource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge two sets of command lines, the defaults and the ones passed in at run time.
|
|
||||||
*
|
|
||||||
* @param defaults the default values
|
|
||||||
* @param args the ones passed in at runtime
|
|
||||||
* @return a new command line
|
|
||||||
*/
|
|
||||||
protected Map<String, Object> mergeCommandLineArgs(String[] defaults, String[] args) {
|
|
||||||
|
|
||||||
if (defaults == null) {
|
|
||||||
defaults = new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> nonopts = new ArrayList<String>();
|
|
||||||
Map<String, Object> options = new LinkedHashMap<String, Object>();
|
|
||||||
|
|
||||||
for (String arg : defaults) {
|
|
||||||
if (isOptionArg(arg)) {
|
|
||||||
addOptionArg(options, arg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nonopts.add(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (String arg : args) {
|
|
||||||
if (isOptionArg(arg)) {
|
|
||||||
addOptionArg(options, arg);
|
|
||||||
}
|
|
||||||
else if (!nonopts.contains(arg)) {
|
|
||||||
nonopts.add(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String key : nonopts) {
|
|
||||||
options.put(key, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isOptionArg(String arg) {
|
|
||||||
return arg.startsWith("--");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addOptionArg(Map<String, Object> map, String arg) {
|
|
||||||
String optionText = arg.substring(2, arg.length());
|
|
||||||
String optionName;
|
|
||||||
String optionValue = "";
|
|
||||||
if (optionText.contains("=")) {
|
|
||||||
optionName = optionText.substring(0, optionText.indexOf('='));
|
|
||||||
optionValue = optionText.substring(optionText.indexOf('=') + 1,
|
|
||||||
optionText.length());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
optionName = optionText;
|
|
||||||
}
|
|
||||||
if (optionName.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
|
|
||||||
}
|
|
||||||
map.put(optionName, optionValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load beans into the application context.
|
* Load beans into the application context.
|
||||||
* @param context the context to load beans into
|
* @param context the context to load beans into
|
||||||
|
@ -552,6 +494,13 @@ public class SpringApplication {
|
||||||
this.addCommandLineProperties = addCommandLineProperties;
|
this.addCommandLineProperties = addCommandLineProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the addCommandLineProperties
|
||||||
|
*/
|
||||||
|
public boolean isAddCommandLineProperties() {
|
||||||
|
return this.addCommandLineProperties;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set some default command line arguments which can be overridden by those passed
|
* Set some default command line arguments which can be overridden by those passed
|
||||||
* into the run methods.
|
* into the run methods.
|
||||||
|
@ -571,12 +520,45 @@ public class SpringApplication {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the underlying environment that should be used when loading.
|
* Sets the underlying environment that should be used when loading.
|
||||||
|
*
|
||||||
* @param environment the environment
|
* @param environment the environment
|
||||||
*/
|
*/
|
||||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The environment that will be used to create the application context (can be null in
|
||||||
|
* which case a default will be provided).
|
||||||
|
*
|
||||||
|
* @return the environment
|
||||||
|
*/
|
||||||
|
public ConfigurableEnvironment getEnvironment() {
|
||||||
|
return this.environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sources that will be used to create an ApplicationContext if this application
|
||||||
|
* {@link #run(String...)} is called.
|
||||||
|
*
|
||||||
|
* @return the sources
|
||||||
|
*/
|
||||||
|
public Set<Object> getSources() {
|
||||||
|
return this.sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sources that will be used to create an ApplicationContext. A valid source is
|
||||||
|
* one of: a class, class name, package, package name, or an XML resource location.
|
||||||
|
* Can also be set using contructors and static convenience methods (e.g.
|
||||||
|
* {@link #run(Object[], String[])}).
|
||||||
|
*
|
||||||
|
* @param sources the sources to set
|
||||||
|
*/
|
||||||
|
public void setSources(Set<Object> sources) {
|
||||||
|
this.sources = sources;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link ResourceLoader} that should be used when loading resources.
|
* Sets the {@link ResourceLoader} that should be used when loading resources.
|
||||||
* @param resourceLoader the resource loader
|
* @param resourceLoader the resource loader
|
||||||
|
@ -660,21 +642,6 @@ public class SpringApplication {
|
||||||
return new SpringApplication(sources).run(args);
|
return new SpringApplication(sources).run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Static helper that can be used to run a {@link SpringApplication} from a script
|
|
||||||
* using the specified sources with default settings. This method is useful when
|
|
||||||
* calling this calls from a script environment that will not have a single main
|
|
||||||
* application class.
|
|
||||||
* @param sources the sources to load
|
|
||||||
* @param args the application arguments (usually passed from a Java main method)
|
|
||||||
* @return the running {@link ApplicationContext}
|
|
||||||
*/
|
|
||||||
public static ApplicationContext runFromScript(Object[] sources, String[] args) {
|
|
||||||
SpringApplication application = new SpringApplication(sources);
|
|
||||||
application.setMainApplicationClass(null);
|
|
||||||
return application.run(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static helper that can be used to exit a {@link SpringApplication} and obtain a
|
* Static helper that can be used to exit a {@link SpringApplication} and obtain a
|
||||||
* code indicating success (0) or otherwise. Does not throw exceptions but should
|
* code indicating success (0) or otherwise. Does not throw exceptions but should
|
||||||
|
|
|
@ -25,9 +25,10 @@ package org.springframework.bootstrap;
|
||||||
public interface SpringApplicationInitializer {
|
public interface SpringApplicationInitializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the applcation
|
* Initialize the application
|
||||||
* @param springApplication the spring application.
|
* @param springApplication the spring application.
|
||||||
|
* @param args the args provided on command line by caller
|
||||||
*/
|
*/
|
||||||
void initialize(SpringApplication springApplication);
|
void initialize(SpringApplication springApplication, String[] args);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public final class DefaultProfileDocumentMatcher implements DocumentMatcher {
|
public class DefaultProfileDocumentMatcher implements DocumentMatcher {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MatchStatus matches(Properties properties) {
|
public MatchStatus matches(Properties properties) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.bootstrap.config;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.core.env.PropertiesPropertySource;
|
import org.springframework.core.env.PropertiesPropertySource;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
@ -38,9 +37,9 @@ public class PropertiesPropertySourceLoader implements PropertySourceLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertySource<?> load(Resource resource, Environment environment) {
|
public PropertySource<?> load(Resource resource) {
|
||||||
try {
|
try {
|
||||||
Properties properties = loadProperties(resource, environment);
|
Properties properties = loadProperties(resource);
|
||||||
return new PropertiesPropertySource(resource.getDescription(), properties);
|
return new PropertiesPropertySource(resource.getDescription(), properties);
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
|
@ -49,8 +48,7 @@ public class PropertiesPropertySourceLoader implements PropertySourceLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Properties loadProperties(Resource resource, Environment environment)
|
protected Properties loadProperties(Resource resource) throws IOException {
|
||||||
throws IOException {
|
|
||||||
return PropertiesLoaderUtils.loadProperties(resource);
|
return PropertiesLoaderUtils.loadProperties(resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.bootstrap.config;
|
package org.springframework.bootstrap.config;
|
||||||
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
@ -37,6 +36,6 @@ public interface PropertySourceLoader {
|
||||||
* Load the resource into a property source.
|
* Load the resource into a property source.
|
||||||
* @return a property source
|
* @return a property source
|
||||||
*/
|
*/
|
||||||
PropertySource<?> load(Resource resource, Environment environment);
|
PropertySource<?> load(Resource resource);
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,15 +16,18 @@
|
||||||
|
|
||||||
package org.springframework.bootstrap.config;
|
package org.springframework.bootstrap.config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DocumentMatcher} backed by {@link Environment#getActiveProfiles()}.
|
* {@link DocumentMatcher} backed by {@link Environment#getActiveProfiles()}. A YAML
|
||||||
|
* document matches if it contains an element "spring.profiles" (a comma-separated list)
|
||||||
|
* and one of the profiles is in the active list.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
|
@ -32,20 +35,20 @@ public class SpringProfileDocumentMatcher implements DocumentMatcher {
|
||||||
|
|
||||||
private static final String[] DEFAULT_PROFILES = new String[] { "default" };
|
private static final String[] DEFAULT_PROFILES = new String[] { "default" };
|
||||||
|
|
||||||
private final Environment environment;
|
private String[] activeProfiles = new String[0];
|
||||||
|
|
||||||
/**
|
public void addActiveProfiles(String... profiles) {
|
||||||
* Create a new {@link SpringProfileDocumentMatcher} instance.
|
LinkedHashSet<String> set = new LinkedHashSet<String>(
|
||||||
* @param environment the environment
|
Arrays.asList(this.activeProfiles));
|
||||||
*/
|
for (String profile : profiles) {
|
||||||
public SpringProfileDocumentMatcher(Environment environment) {
|
set.add(profile);
|
||||||
Assert.notNull(environment, "Environment must not be null");
|
}
|
||||||
this.environment = environment;
|
this.activeProfiles = set.toArray(new String[set.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MatchStatus matches(Properties properties) {
|
public MatchStatus matches(Properties properties) {
|
||||||
String[] profiles = this.environment.getActiveProfiles();
|
String[] profiles = this.activeProfiles;
|
||||||
if (profiles.length == 0) {
|
if (profiles.length == 0) {
|
||||||
profiles = DEFAULT_PROFILES;
|
profiles = DEFAULT_PROFILES;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,13 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy to load '.yml' files into a {@link PropertySource}.
|
* Strategy to load '.yml' files into a {@link PropertySource}.
|
||||||
|
@ -49,8 +51,7 @@ public class YamlPropertySourceLoader extends PropertiesPropertySourceLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Properties loadProperties(final Resource resource,
|
protected Properties loadProperties(final Resource resource) throws IOException {
|
||||||
final Environment environment) throws IOException {
|
|
||||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||||
if (this.matchers != null && !this.matchers.isEmpty()) {
|
if (this.matchers != null && !this.matchers.isEmpty()) {
|
||||||
factory.setMatchDefault(false);
|
factory.setMatchDefault(false);
|
||||||
|
@ -74,13 +75,31 @@ public class YamlPropertySourceLoader extends PropertiesPropertySourceLoader {
|
||||||
* which have an explicit "spring.profiles.active" value in the current active
|
* which have an explicit "spring.profiles.active" value in the current active
|
||||||
* profiles.
|
* profiles.
|
||||||
*
|
*
|
||||||
|
* @param activeProfiles the active profiles to match independent of file contents
|
||||||
|
*
|
||||||
* @return a property source loader
|
* @return a property source loader
|
||||||
*/
|
*/
|
||||||
public static YamlPropertySourceLoader springProfileAwareLoader(
|
public static YamlPropertySourceLoader springProfileAwareLoader(
|
||||||
Environment environment) {
|
String[] activeProfiles) {
|
||||||
return new YamlPropertySourceLoader(
|
final SpringProfileDocumentMatcher matcher = new SpringProfileDocumentMatcher();
|
||||||
new SpringProfileDocumentMatcher(environment),
|
for (String profile : activeProfiles) {
|
||||||
new DefaultProfileDocumentMatcher());
|
matcher.addActiveProfiles(profile);
|
||||||
|
}
|
||||||
|
return new YamlPropertySourceLoader(matcher, new DefaultProfileDocumentMatcher() {
|
||||||
|
@Override
|
||||||
|
public MatchStatus matches(Properties properties) {
|
||||||
|
MatchStatus result = super.matches(properties);
|
||||||
|
if (result == MatchStatus.FOUND) {
|
||||||
|
Set<String> profiles = StringUtils.commaDelimitedListToSet(properties
|
||||||
|
.getProperty("spring.profiles.active", ""));
|
||||||
|
for (String profile : profiles) {
|
||||||
|
// allow document with no profile to set the active one
|
||||||
|
matcher.addActiveProfiles(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,20 +17,35 @@
|
||||||
package org.springframework.bootstrap.context.initializer;
|
package org.springframework.bootstrap.context.initializer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.bootstrap.config.SpringProfileDocumentMatcher;
|
import org.springframework.beans.PropertyValues;
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.bootstrap.SpringApplicationInitializer;
|
||||||
|
import org.springframework.bootstrap.bind.PropertySourcesPropertyValues;
|
||||||
|
import org.springframework.bootstrap.bind.RelaxedDataBinder;
|
||||||
import org.springframework.bootstrap.config.PropertiesPropertySourceLoader;
|
import org.springframework.bootstrap.config.PropertiesPropertySourceLoader;
|
||||||
import org.springframework.bootstrap.config.PropertySourceLoader;
|
import org.springframework.bootstrap.config.PropertySourceLoader;
|
||||||
import org.springframework.bootstrap.config.YamlPropertySourceLoader;
|
import org.springframework.bootstrap.config.YamlPropertySourceLoader;
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.core.env.CommandLinePropertySource;
|
import org.springframework.core.env.CommandLinePropertySource;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.MapPropertySource;
|
||||||
import org.springframework.core.env.MutablePropertySources;
|
import org.springframework.core.env.MutablePropertySources;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +59,7 @@ import org.springframework.util.StringUtils;
|
||||||
* <li>classpath:config/</li>
|
* <li>classpath:config/</li>
|
||||||
* <li>file:./config/:</li>
|
* <li>file:./config/:</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Alternative locations and names can be specified using
|
* Alternative locations and names can be specified using
|
||||||
* {@link #setSearchLocations(String[])} and {@link #setName(String)}.
|
* {@link #setSearchLocations(String[])} and {@link #setName(String)}.
|
||||||
|
@ -62,7 +78,8 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
public class ConfigFileApplicationContextInitializer implements
|
public class ConfigFileApplicationContextInitializer implements
|
||||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
ApplicationContextInitializer<ConfigurableApplicationContext>,
|
||||||
|
SpringApplicationInitializer, Ordered {
|
||||||
|
|
||||||
private static final String LOCATION_VARIABLE = "${spring.config.location}";
|
private static final String LOCATION_VARIABLE = "${spring.config.location}";
|
||||||
|
|
||||||
|
@ -73,24 +90,76 @@ public class ConfigFileApplicationContextInitializer implements
|
||||||
|
|
||||||
private int order = Integer.MIN_VALUE + 10;
|
private int order = Integer.MIN_VALUE + 10;
|
||||||
|
|
||||||
|
private Map<String, PropertySource<?>> cached = new HashMap<String, PropertySource<?>>();
|
||||||
|
|
||||||
|
private ConversionService conversionService = new DefaultConversionService();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a property source from the command line, loads additional external
|
||||||
|
* configuration, and then binds it to the application. This makes it possible to set
|
||||||
|
* things dynamically, like the sources ("spring.main.sources" - a CSV list) the flag
|
||||||
|
* to indicate a web environment ("spring.main.web_environment=true") or the flag to
|
||||||
|
* switch off the banner ("spring.main.show_banner=false").
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize(SpringApplication application, String[] args) {
|
||||||
|
|
||||||
|
if (application.isAddCommandLineProperties()) {
|
||||||
|
this.cached.put(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||||
|
new MapPropertySource(
|
||||||
|
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||||
|
extractCommandLineArgs(args)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigurableEnvironment environment = application.getEnvironment();
|
||||||
|
if (environment == null) {
|
||||||
|
environment = new StandardEnvironment();
|
||||||
|
}
|
||||||
|
load(environment, new DefaultResourceLoader());
|
||||||
|
|
||||||
|
// Set bean properties from command line args parameters.
|
||||||
|
PropertyValues pvs = new PropertySourcesPropertyValues(
|
||||||
|
environment.getPropertySources());
|
||||||
|
RelaxedDataBinder binder = new RelaxedDataBinder(application, "spring.main");
|
||||||
|
binder.setConversionService(this.conversionService);
|
||||||
|
binder.bind(pvs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||||
|
load(applicationContext.getEnvironment(), applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
|
||||||
|
|
||||||
List<String> candidates = getCandidateLocations();
|
List<String> candidates = getCandidateLocations();
|
||||||
|
|
||||||
|
if (this.cached
|
||||||
|
.containsKey(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||||
|
environment
|
||||||
|
.getPropertySources()
|
||||||
|
.addFirst(
|
||||||
|
this.cached
|
||||||
|
.get(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
// Initial load allows profiles to be activated
|
// Initial load allows profiles to be activated
|
||||||
for (String candidate : candidates) {
|
for (String candidate : candidates) {
|
||||||
load(applicationContext, candidate, null);
|
load(environment, resourceLoader, candidate, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second load for specific profiles
|
// Second load for specific profiles
|
||||||
for (String profile : applicationContext.getEnvironment().getActiveProfiles()) {
|
for (String profile : environment.getActiveProfiles()) {
|
||||||
for (String candidate : candidates) {
|
for (String candidate : candidates) {
|
||||||
load(applicationContext, candidate, profile);
|
load(environment, resourceLoader, candidate, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getCandidateLocations() {
|
private List<String> getCandidateLocations() {
|
||||||
|
|
||||||
List<String> candidates = new ArrayList<String>();
|
List<String> candidates = new ArrayList<String>();
|
||||||
for (String searchLocation : this.searchLocations) {
|
for (String searchLocation : this.searchLocations) {
|
||||||
for (String extension : new String[] { ".properties", ".yml" }) {
|
for (String extension : new String[] { ".properties", ".yml" }) {
|
||||||
|
@ -100,38 +169,118 @@ public class ConfigFileApplicationContextInitializer implements
|
||||||
}
|
}
|
||||||
candidates.add(LOCATION_VARIABLE);
|
candidates.add(LOCATION_VARIABLE);
|
||||||
return candidates;
|
return candidates;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load(ConfigurableApplicationContext applicationContext, String location,
|
private void load(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
|
||||||
String profile) {
|
String location, String profile) {
|
||||||
|
|
||||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
|
||||||
location = environment.resolvePlaceholders(location);
|
location = environment.resolvePlaceholders(location);
|
||||||
String suffix = "." + StringUtils.getFilenameExtension(location);
|
String suffix = "." + StringUtils.getFilenameExtension(location);
|
||||||
|
|
||||||
if (StringUtils.hasLength(profile)) {
|
if (StringUtils.hasLength(profile)) {
|
||||||
location = location.replace(suffix, "-" + profile + suffix);
|
location = location.replace(suffix, "-" + profile + suffix);
|
||||||
}
|
}
|
||||||
PropertySourceLoader[] loaders = {
|
|
||||||
new PropertiesPropertySourceLoader(),
|
|
||||||
new YamlPropertySourceLoader(new SpringProfileDocumentMatcher(environment),
|
|
||||||
new ProfileSettingDocumentMatcher(environment)) };
|
|
||||||
for (PropertySourceLoader loader : loaders) {
|
|
||||||
Resource resource = applicationContext.getResource(location);
|
|
||||||
if (resource != null && resource.exists() && loader.supports(resource)) {
|
|
||||||
PropertySource<?> propertySource = loader.load(resource, environment);
|
|
||||||
MutablePropertySources propertySources = environment.getPropertySources();
|
|
||||||
if (propertySources
|
|
||||||
.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
|
||||||
propertySources.addAfter(
|
|
||||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
|
||||||
propertySource);
|
|
||||||
|
|
||||||
} else {
|
List<PropertySourceLoader> loaders = new ArrayList<PropertySourceLoader>();
|
||||||
propertySources.addFirst(propertySource);
|
loaders.add(new PropertiesPropertySourceLoader());
|
||||||
}
|
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
|
||||||
return;
|
loaders.add(YamlPropertySourceLoader.springProfileAwareLoader(environment
|
||||||
|
.getActiveProfiles()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource resource = resourceLoader.getResource(location);
|
||||||
|
PropertySource<?> propertySource = getPropertySource(resource, loaders);
|
||||||
|
if (propertySource == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (propertySource.containsProperty("spring.profiles.active")) {
|
||||||
|
Set<String> profiles = StringUtils.commaDelimitedListToSet(propertySource
|
||||||
|
.getProperty("spring.profiles.active").toString());
|
||||||
|
for (String active : profiles) {
|
||||||
|
// allow document with no profile to set the active one
|
||||||
|
environment.addActiveProfile(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
MutablePropertySources propertySources = environment.getPropertySources();
|
||||||
|
if (propertySources
|
||||||
|
.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||||
|
propertySources.addAfter(
|
||||||
|
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||||
|
propertySource);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
propertySources.addFirst(propertySource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertySource<?> getPropertySource(Resource resource,
|
||||||
|
List<PropertySourceLoader> loaders) {
|
||||||
|
String key = resource.getDescription();
|
||||||
|
if (this.cached.containsKey(key)) {
|
||||||
|
return this.cached.get(key);
|
||||||
|
}
|
||||||
|
for (PropertySourceLoader loader : loaders) {
|
||||||
|
if (resource != null && resource.exists() && loader.supports(resource)) {
|
||||||
|
PropertySource<?> propertySource = loader.load(resource);
|
||||||
|
this.cached.put(key, propertySource);
|
||||||
|
return propertySource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge two sets of command lines, the defaults and the ones passed in at run time.
|
||||||
|
*
|
||||||
|
* @param args the ones passed in at runtime
|
||||||
|
* @return a new command line
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> extractCommandLineArgs(String[] args) {
|
||||||
|
|
||||||
|
List<String> nonopts = new ArrayList<String>();
|
||||||
|
Map<String, Object> options = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
|
for (String arg : args) {
|
||||||
|
if (isOptionArg(arg)) {
|
||||||
|
addOptionArg(options, arg);
|
||||||
|
}
|
||||||
|
else if (!nonopts.contains(arg)) {
|
||||||
|
nonopts.add(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : nonopts) {
|
||||||
|
options.put(key, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOptionArg(String arg) {
|
||||||
|
return arg.startsWith("--");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOptionArg(Map<String, Object> map, String arg) {
|
||||||
|
String optionText = arg.substring(2, arg.length());
|
||||||
|
String optionName;
|
||||||
|
String optionValue = "";
|
||||||
|
if (optionText.contains("=")) {
|
||||||
|
optionName = optionText.substring(0, optionText.indexOf('='));
|
||||||
|
optionValue = optionText.substring(optionText.indexOf('=') + 1,
|
||||||
|
optionText.length());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
optionName = optionText;
|
||||||
|
}
|
||||||
|
if (optionName.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
|
||||||
|
}
|
||||||
|
map.put(optionName, optionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrder(int order) {
|
public void setOrder(int order) {
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class LoggingApplicationContextInitializer implements
|
||||||
private int order = Integer.MIN_VALUE + 11;
|
private int order = Integer.MIN_VALUE + 11;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(SpringApplication springApplication) {
|
public void initialize(SpringApplication springApplication, String[] args) {
|
||||||
LoggingSystem.get(springApplication.getClass().getClassLoader())
|
LoggingSystem.get(springApplication.getClass().getClassLoader())
|
||||||
.beforeInitialize();
|
.beforeInitialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +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.initializer;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
|
||||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link DocumentMatcher} that sets the active profile if it finds a document with a
|
|
||||||
* key <code>spring.profiles.active</code>.
|
|
||||||
*
|
|
||||||
* @author Dave Syer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ProfileSettingDocumentMatcher implements DocumentMatcher {
|
|
||||||
|
|
||||||
private final Environment environment;
|
|
||||||
|
|
||||||
public ProfileSettingDocumentMatcher(Environment environment) {
|
|
||||||
this.environment = environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MatchStatus matches(Properties properties) {
|
|
||||||
if (!properties.containsKey("spring.profiles")) {
|
|
||||||
Set<String> profiles = StringUtils.commaDelimitedListToSet(properties
|
|
||||||
.getProperty("spring.profiles.active", ""));
|
|
||||||
if (this.environment instanceof ConfigurableEnvironment) {
|
|
||||||
ConfigurableEnvironment configurable = (ConfigurableEnvironment) this.environment;
|
|
||||||
for (String profile : profiles) {
|
|
||||||
// allow document with no profile to set the active one
|
|
||||||
configurable.addActiveProfile(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// matches default profile
|
|
||||||
return MatchStatus.FOUND;
|
|
||||||
} else {
|
|
||||||
return MatchStatus.NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -157,15 +157,14 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
private PropertySources loadPropertySources(String[] path) {
|
private PropertySources loadPropertySources(String[] path) {
|
||||||
MutablePropertySources propertySources = new MutablePropertySources();
|
MutablePropertySources propertySources = new MutablePropertySources();
|
||||||
PropertySourceLoader[] loaders = { new PropertiesPropertySourceLoader(),
|
PropertySourceLoader[] loaders = { new PropertiesPropertySourceLoader(),
|
||||||
YamlPropertySourceLoader.springProfileAwareLoader(this.environment) };
|
YamlPropertySourceLoader.springProfileAwareLoader(environment.getActiveProfiles()) };
|
||||||
for (String location : path) {
|
for (String location : path) {
|
||||||
location = this.environment.resolvePlaceholders(location);
|
location = this.environment.resolvePlaceholders(location);
|
||||||
Resource resource = this.resourceLoader.getResource(location);
|
Resource resource = this.resourceLoader.getResource(location);
|
||||||
if (resource != null && resource.exists()) {
|
if (resource != null && resource.exists()) {
|
||||||
for (PropertySourceLoader loader : loaders) {
|
for (PropertySourceLoader loader : loaders) {
|
||||||
if (loader.supports(resource)) {
|
if (loader.supports(resource)) {
|
||||||
PropertySource<?> propertySource = loader.load(resource,
|
PropertySource<?> propertySource = loader.load(resource);
|
||||||
this.environment);
|
|
||||||
propertySources.addFirst(propertySource);
|
propertySources.addFirst(propertySource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-/tmp/}spring.log}"/>
|
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-/tmp/}spring.log}"/>
|
||||||
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- %-40.40logger{39} : %m [%t]%n%wex"/>
|
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } [%t] --- %-40.40logger{39} : %m%n%wex"/>
|
||||||
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m %clr([%t]){faint}%n%wex"/>
|
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex"/>
|
||||||
|
|
||||||
<conversionRule conversionWord="clr" converterClass="org.springframework.bootstrap.logging.logback.ColorConverter" />
|
<conversionRule conversionWord="clr" converterClass="org.springframework.bootstrap.logging.logback.ColorConverter" />
|
||||||
<conversionRule conversionWord="wex" converterClass="org.springframework.bootstrap.logging.logback.WhitespaceThrowableProxyConverter" />
|
<conversionRule conversionWord="wex" converterClass="org.springframework.bootstrap.logging.logback.WhitespaceThrowableProxyConverter" />
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link SpringApplication} main method.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SimpleMainTests {
|
||||||
|
|
||||||
|
private PrintStream savedOutput;
|
||||||
|
private ByteArrayOutputStream output;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void open() {
|
||||||
|
this.savedOutput = System.out;
|
||||||
|
this.output = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(this.output));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
System.setOut(this.savedOutput);
|
||||||
|
System.out.println(getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void emptyApplicationContext() throws Exception {
|
||||||
|
SpringApplication.main(getArgs());
|
||||||
|
assertTrue(getOutput().contains("Pre-instantiating singletons"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basePackageScan() throws Exception {
|
||||||
|
SpringApplication.main(getArgs(ClassUtils.getPackageName(getClass())
|
||||||
|
+ ".sampleconfig"));
|
||||||
|
assertTrue(getOutput().contains("Pre-instantiating singletons"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configClassContext() throws Exception {
|
||||||
|
SpringApplication.main(getArgs(getClass().getName()));
|
||||||
|
assertTrue(getOutput().contains("Pre-instantiating singletons"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void xmlContext() throws Exception {
|
||||||
|
SpringApplication.main(getArgs("org/springframework/bootstrap/sample-beans.xml"));
|
||||||
|
assertTrue(getOutput().contains("Pre-instantiating singletons"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mixedContext() throws Exception {
|
||||||
|
SpringApplication.main(getArgs(getClass().getName(),
|
||||||
|
"org/springframework/bootstrap/sample-beans.xml"));
|
||||||
|
assertTrue(getOutput().contains("Pre-instantiating singletons"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getArgs(String... args) {
|
||||||
|
List<String> list = new ArrayList<String>(Arrays.asList(
|
||||||
|
"--spring.main.webEnvironment=false", "--spring.main.showBanner=false"));
|
||||||
|
if (args.length > 0) {
|
||||||
|
list.add("--spring.main.sources="
|
||||||
|
+ StringUtils.arrayToCommaDelimitedString(args));
|
||||||
|
}
|
||||||
|
return list.toArray(new String[list.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getOutput() {
|
||||||
|
return this.output.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,10 +26,6 @@ import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
|
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
|
||||||
import org.springframework.bootstrap.BeanDefinitionLoader;
|
|
||||||
import org.springframework.bootstrap.CommandLineRunner;
|
|
||||||
import org.springframework.bootstrap.ExitCodeGenerator;
|
|
||||||
import org.springframework.bootstrap.SpringApplication;
|
|
||||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -94,14 +90,14 @@ public class SpringApplicationTests {
|
||||||
public void sourcesMustNotBeNull() throws Exception {
|
public void sourcesMustNotBeNull() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("Sources must not be empty");
|
this.thrown.expectMessage("Sources must not be empty");
|
||||||
new SpringApplication((Object[]) null);
|
new SpringApplication((Object[]) null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sourcesMustNotBeEmpty() throws Exception {
|
public void sourcesMustNotBeEmpty() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("Sources must not be empty");
|
this.thrown.expectMessage("Sources must not be empty");
|
||||||
new SpringApplication();
|
new SpringApplication().run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -270,7 +266,7 @@ public class SpringApplicationTests {
|
||||||
application.setWebEnvironment(false);
|
application.setWebEnvironment(false);
|
||||||
application.setUseMockLoader(true);
|
application.setUseMockLoader(true);
|
||||||
application.run();
|
application.run();
|
||||||
assertThat(application.getSources(), equalTo(sources));
|
assertThat(application.getSources().toArray(), equalTo(sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -341,8 +337,6 @@ public class SpringApplicationTests {
|
||||||
|
|
||||||
private boolean useMockLoader;
|
private boolean useMockLoader;
|
||||||
|
|
||||||
private Object[] sources;
|
|
||||||
|
|
||||||
public TestSpringApplication(Object... sources) {
|
public TestSpringApplication(Object... sources) {
|
||||||
super(sources);
|
super(sources);
|
||||||
}
|
}
|
||||||
|
@ -358,7 +352,6 @@ public class SpringApplicationTests {
|
||||||
@Override
|
@Override
|
||||||
protected BeanDefinitionLoader createBeanDefinitionLoader(
|
protected BeanDefinitionLoader createBeanDefinitionLoader(
|
||||||
BeanDefinitionRegistry registry, Object[] sources) {
|
BeanDefinitionRegistry registry, Object[] sources) {
|
||||||
this.sources = sources;
|
|
||||||
if (this.useMockLoader) {
|
if (this.useMockLoader) {
|
||||||
this.loader = mock(BeanDefinitionLoader.class);
|
this.loader = mock(BeanDefinitionLoader.class);
|
||||||
}
|
}
|
||||||
|
@ -372,9 +365,6 @@ public class SpringApplicationTests {
|
||||||
return this.loader;
|
return this.loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getSources() {
|
|
||||||
return this.sources;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
|
@ -20,11 +20,15 @@ import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.validation.Constraint;
|
import javax.validation.Constraint;
|
||||||
import javax.validation.ConstraintValidator;
|
import javax.validation.ConstraintValidator;
|
||||||
|
@ -36,7 +40,7 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.bootstrap.bind.RelaxedDataBinder;
|
import org.springframework.beans.NotWritablePropertyException;
|
||||||
import org.springframework.context.support.StaticMessageSource;
|
import org.springframework.context.support.StaticMessageSource;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.convert.support.DefaultConversionService;
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
|
@ -119,20 +123,50 @@ public class RelaxedDataBinderTests {
|
||||||
@Test
|
@Test
|
||||||
public void testBindNestedList() throws Exception {
|
public void testBindNestedList() throws Exception {
|
||||||
TargetWithNestedList target = new TargetWithNestedList();
|
TargetWithNestedList target = new TargetWithNestedList();
|
||||||
bind(target, "nested: bar,foo");
|
bind(target, "nested[0]: bar\nnested[1]: foo");
|
||||||
bind(target, "nested[0]: bar");
|
|
||||||
bind(target, "nested[1]: foo");
|
|
||||||
assertEquals("[bar, foo]", target.getNested().toString());
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindNestedListCommaDelimitedONly() throws Exception {
|
public void testBindNestedListCommaDelimitedOnly() throws Exception {
|
||||||
TargetWithNestedList target = new TargetWithNestedList();
|
TargetWithNestedList target = new TargetWithNestedList();
|
||||||
this.conversionService = new DefaultConversionService();
|
this.conversionService = new DefaultConversionService();
|
||||||
bind(target, "nested: bar,foo");
|
bind(target, "nested: bar,foo");
|
||||||
assertEquals("[bar, foo]", target.getNested().toString());
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindNestedSetCommaDelimitedOnly() throws Exception {
|
||||||
|
TargetWithNestedSet target = new TargetWithNestedSet();
|
||||||
|
this.conversionService = new DefaultConversionService();
|
||||||
|
bind(target, "nested: bar,foo");
|
||||||
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NotWritablePropertyException.class)
|
||||||
|
public void testBindNestedReadOnlyListCommaSeparated() throws Exception {
|
||||||
|
TargetWithReadOnlyNestedList target = new TargetWithReadOnlyNestedList();
|
||||||
|
this.conversionService = new DefaultConversionService();
|
||||||
|
bind(target, "nested: bar,foo");
|
||||||
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindNestedReadOnlyListIndexed() throws Exception {
|
||||||
|
TargetWithReadOnlyNestedList target = new TargetWithReadOnlyNestedList();
|
||||||
|
this.conversionService = new DefaultConversionService();
|
||||||
|
bind(target, "nested[0]: bar\nnested[1]:foo");
|
||||||
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindNestedReadOnlyCollectionIndexed() throws Exception {
|
||||||
|
TargetWithReadOnlyNestedCollection target = new TargetWithReadOnlyNestedCollection();
|
||||||
|
this.conversionService = new DefaultConversionService();
|
||||||
|
bind(target, "nested[0]: bar\nnested[1]:foo");
|
||||||
|
assertEquals("[bar, foo]", target.getNested().toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindNestedMap() throws Exception {
|
public void testBindNestedMap() throws Exception {
|
||||||
TargetWithNestedMap target = new TargetWithNestedMap();
|
TargetWithNestedMap target = new TargetWithNestedMap();
|
||||||
|
@ -306,6 +340,34 @@ public class RelaxedDataBinderTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TargetWithReadOnlyNestedList {
|
||||||
|
private List<String> nested = new ArrayList<String>();
|
||||||
|
|
||||||
|
public List<String> getNested() {
|
||||||
|
return this.nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TargetWithReadOnlyNestedCollection {
|
||||||
|
private Collection<String> nested = new ArrayList<String>();
|
||||||
|
|
||||||
|
public Collection<String> getNested() {
|
||||||
|
return this.nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TargetWithNestedSet {
|
||||||
|
private Set<String> nested = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
public Set<String> getNested() {
|
||||||
|
return this.nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNested(Set<String> nested) {
|
||||||
|
this.nested = nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TargetWithNestedObject {
|
public static class TargetWithNestedObject {
|
||||||
private VanillaTarget nested;
|
private VanillaTarget nested;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample config for tests
|
||||||
|
*/
|
||||||
|
package org.springframework.bootstrap.sampleconfig;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
main.sources: org.springframework.bootstrap.main.DispatcherMainTests
|
Loading…
Reference in New Issue