Use new configuration properties in spring-boot

Update `spring-boot` to use the new configuration properties support.

See gh-9000
pull/8802/merge
Madhura Bhave 8 years ago committed by Phillip Webb
parent 834aa09300
commit d4ef523e64

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,9 +33,7 @@ import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiColors; import org.springframework.boot.ansi.AnsiColors;
import org.springframework.boot.ansi.AnsiElement; import org.springframework.boot.ansi.AnsiElement;
import org.springframework.boot.ansi.AnsiOutput; import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -45,6 +43,7 @@ import org.springframework.util.Assert;
* *
* @author Craig Burke * @author Craig Burke
* @author Phillip Webb * @author Phillip Webb
* @author Madhura Bhave
* @since 1.4.0 * @since 1.4.0
*/ */
public class ImageBanner implements Banner { public class ImageBanner implements Banner {
@ -92,12 +91,11 @@ public class ImageBanner implements Banner {
private void printBanner(Environment environment, PrintStream out) private void printBanner(Environment environment, PrintStream out)
throws IOException { throws IOException {
PropertyResolver properties = new RelaxedPropertyResolver(environment, int width = environment.getProperty("banner.image.width", Integer.class, 76);
"banner.image."); int height = environment.getProperty("banner.image.height", Integer.class, 0);
int width = properties.getProperty("width", Integer.class, 76); int margin = environment.getProperty("banner.image.margin", Integer.class, 2);
int height = properties.getProperty("height", Integer.class, 0); boolean invert = environment.getProperty("banner.image.invert", Boolean.class,
int margin = properties.getProperty("margin", Integer.class, 2); false);
boolean invert = properties.getProperty("invert", Boolean.class, false);
BufferedImage image = readImage(width, height); BufferedImage image = readImage(width, height);
printBanner(image, margin, invert, out); printBanner(image, margin, invert, out);
} }

@ -40,8 +40,8 @@ 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.xml.XmlBeanDefinitionReader; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.Banner.Mode; import org.springframework.boot.Banner.Mode;
import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
@ -55,8 +55,6 @@ 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.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.CompositePropertySource; import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
@ -76,7 +74,6 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StandardServletEnvironment; import org.springframework.web.context.support.StandardServletEnvironment;
@ -578,9 +575,8 @@ public class SpringApplication {
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) { private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty( if (System.getProperty(
CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) { CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment, Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
"spring.beaninfo."); Boolean.class, Boolean.TRUE);
Boolean ignore = resolver.getProperty("ignore", Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
ignore.toString()); ignore.toString());
} }
@ -591,16 +587,10 @@ public class SpringApplication {
* @param environment the environment to bind * @param environment the environment to bind
*/ */
protected void bindToSpringApplication(ConfigurableEnvironment environment) { protected void bindToSpringApplication(ConfigurableEnvironment environment) {
PropertiesConfigurationFactory<SpringApplication> binder = new PropertiesConfigurationFactory<>(
this);
ConversionService conversionService = new DefaultConversionService();
binder.setTargetName("spring.main");
binder.setConversionService(conversionService);
binder.setPropertySources(environment.getPropertySources());
try { try {
binder.bindPropertiesToTarget(); Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
} }
catch (BindException ex) { catch (Exception ex) {
throw new IllegalStateException("Cannot bind to SpringApplication", ex); throw new IllegalStateException("Cannot bind to SpringApplication", ex);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,10 +19,10 @@ package org.springframework.boot.context;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
/** /**
* An {@link ApplicationListener} that halts application startup if the system file * An {@link ApplicationListener} that halts application startup if the system file
@ -42,6 +42,7 @@ import org.springframework.core.Ordered;
* character-encoding value (e.g. "en_GB.UTF-8"). * character-encoding value (e.g. "en_GB.UTF-8").
* *
* @author Dave Syer * @author Dave Syer
* @author Madhura Bhave
*/ */
public class FileEncodingApplicationListener public class FileEncodingApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered { implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
@ -56,11 +57,12 @@ public class FileEncodingApplicationListener
@Override @Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( ConfigurableEnvironment environment = event.getEnvironment();
event.getEnvironment(), "spring."); if (!environment.containsProperty("spring.mandatory-file-encoding")) {
if (resolver.containsProperty("mandatoryFileEncoding")) { return;
}
String encoding = System.getProperty("file.encoding"); String encoding = System.getProperty("file.encoding");
String desired = resolver.getProperty("mandatoryFileEncoding"); String desired = environment.getProperty("spring.mandatory-file-encoding");
if (encoding != null && !desired.equalsIgnoreCase(encoding)) { if (encoding != null && !desired.equalsIgnoreCase(encoding)) {
logger.error("System property 'file.encoding' is currently '" + encoding logger.error("System property 'file.encoding' is currently '" + encoding
+ "'. It should be '" + desired + "'. It should be '" + desired
@ -73,9 +75,7 @@ public class FileEncodingApplicationListener
+ desired + "'."); + desired + "'.");
throw new IllegalStateException( throw new IllegalStateException(
"The Java Virtual Machine has not been configured to use the " "The Java Virtual Machine has not been configured to use the "
+ "desired default character encoding (" + desired + "desired default character encoding (" + desired + ").");
+ ").");
}
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,10 +18,11 @@ package org.springframework.boot.context.config;
import org.springframework.boot.ansi.AnsiOutput; import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiOutput.Enabled; import org.springframework.boot.ansi.AnsiOutput.Enabled;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
/** /**
* An {@link ApplicationListener} that configures {@link AnsiOutput} depending on the * An {@link ApplicationListener} that configures {@link AnsiOutput} depending on the
@ -29,6 +30,7 @@ import org.springframework.core.Ordered;
* values. * values.
* *
* @author Raphael von der Grün * @author Raphael von der Grün
* @author Madhura Bhave
* @since 1.2.0 * @since 1.2.0
*/ */
public class AnsiOutputApplicationListener public class AnsiOutputApplicationListener
@ -36,23 +38,17 @@ public class AnsiOutputApplicationListener
@Override @Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( ConfigurableEnvironment environment = event.getEnvironment();
event.getEnvironment(), "spring.output.ansi."); Binder.get(environment)
if (resolver.containsProperty("enabled")) { .bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class)
String enabled = resolver.getProperty("enabled"); .ifBound(AnsiOutput::setEnabled);
AnsiOutput.setEnabled(Enum.valueOf(Enabled.class, enabled.toUpperCase())); AnsiOutput.setConsoleAvailable(environment
} .getProperty("spring.output.ansi.console-available", Boolean.class));
if (resolver.containsProperty("console-available")) {
AnsiOutput.setConsoleAvailable(
resolver.getProperty("console-available", Boolean.class));
}
} }
@Override @Override
public int getOrder() { public int getOrder() {
// Apply after ConfigFileApplicationListener has called all // Apply after ConfigFileApplicationListener has called EnvironmentPostProcessors
// EnvironmentPostProcessors
return ConfigFileApplicationListener.DEFAULT_ORDER + 1; return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
} }

@ -34,10 +34,11 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.env.EnumerableCompositePropertySource; import org.springframework.boot.env.EnumerableCompositePropertySource;
import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertySourcesLoader; import org.springframework.boot.env.PropertySourcesLoader;
@ -90,6 +91,7 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Madhura Bhave
*/ */
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
ApplicationListener<ApplicationEvent>, Ordered { ApplicationListener<ApplicationEvent>, Ordered {
@ -256,8 +258,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
private void reorderSources(ConfigurableEnvironment environment) { private void reorderSources(ConfigurableEnvironment environment) {
ConfigurationPropertySources LoadedPropertySources.finishAndRelocate(environment.getPropertySources());
.finishAndRelocate(environment.getPropertySources());
PropertySource<?> defaultProperties = environment.getPropertySources() PropertySource<?> defaultProperties = environment.getPropertySources()
.remove(DEFAULT_PROPERTIES); .remove(DEFAULT_PROPERTIES);
if (defaultProperties != null) { if (defaultProperties != null) {
@ -344,11 +345,11 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
// Any pre-existing active profiles set via property sources (e.g. System // Any pre-existing active profiles set via property sources (e.g. System
// properties) take precedence over those added in config files. // properties) take precedence over those added in config files.
SpringProfiles springProfiles = bindSpringProfiles( Set<Profile> active = getProfiles(this.environment, "spring.profiles.active");
this.environment.getPropertySources()); Set<Profile> activeProfiles = new LinkedHashSet<>(active);
Set<Profile> activeProfiles = new LinkedHashSet<>( Set<Profile> include = getProfiles(this.environment,
springProfiles.getActiveProfiles()); "spring.profiles.include");
activeProfiles.addAll(springProfiles.getIncludeProfiles()); activeProfiles.addAll(include);
maybeActivateProfiles(activeProfiles); maybeActivateProfiles(activeProfiles);
return activeProfiles; return activeProfiles;
} }
@ -474,33 +475,34 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
private void handleProfileProperties(PropertySource<?> propertySource) { private void handleProfileProperties(PropertySource<?> propertySource) {
SpringProfiles springProfiles = bindSpringProfiles(propertySource);
maybeActivateProfiles(springProfiles.getActiveProfiles());
addProfiles(springProfiles.getIncludeProfiles());
}
private SpringProfiles bindSpringProfiles(PropertySource<?> propertySource) {
MutablePropertySources propertySources = new MutablePropertySources(); MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(propertySource); propertySources.addFirst(propertySource);
return bindSpringProfiles(propertySources); Set<Profile> active = getProfiles(propertySources, "spring.profiles.active");
Set<Profile> include = getProfiles(propertySources,
"spring.profiles.include");
maybeActivateProfiles(active);
addProfiles(include);
} }
private SpringProfiles bindSpringProfiles(PropertySources propertySources) { private Set<Profile> getProfiles(ConfigurableEnvironment environment,
SpringProfiles springProfiles = new SpringProfiles(); String name) {
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles, return getProfiles(environment.getPropertySources(), name);
"spring.profiles");
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));
springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
} }
private List<String> resolvePlaceholders(List<String> values) { private Set<Profile> getProfiles(PropertySources sources, String name) {
List<String> resolved = new ArrayList<>(); Binder binder = new Binder(ConfigurationPropertySources.get(sources),
for (String value : values) { new PropertySourcesPlaceholdersResolver(this.environment));
resolved.add(this.environment.resolvePlaceholders(value)); return binder.bind(name, String[].class).map(this::asProfileSet)
.orElse(Collections.emptySet());
} }
return resolved;
private Set<Profile> asProfileSet(String[] profileNames) {
List<Profile> profiles = new ArrayList<>();
for (String profileName : profileNames) {
profiles.add(new Profile(profileName));
}
Collections.reverse(profiles);
return new LinkedHashSet<>(profiles);
} }
private void maybeActivateProfiles(Set<Profile> profiles) { private void maybeActivateProfiles(Set<Profile> profiles) {
@ -601,19 +603,17 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
for (PropertySource<?> item : sources) { for (PropertySource<?> item : sources) {
reorderedSources.add(item); reorderedSources.add(item);
} }
addConfigurationProperties( addConfigurationProperties(new LoadedPropertySources(reorderedSources));
new ConfigurationPropertySources(reorderedSources));
} }
private void addConfigurationProperties( private void addConfigurationProperties(LoadedPropertySources loadedSources) {
ConfigurationPropertySources configurationSources) {
MutablePropertySources existingSources = this.environment MutablePropertySources existingSources = this.environment
.getPropertySources(); .getPropertySources();
if (existingSources.contains(DEFAULT_PROPERTIES)) { if (existingSources.contains(DEFAULT_PROPERTIES)) {
existingSources.addBefore(DEFAULT_PROPERTIES, configurationSources); existingSources.addBefore(DEFAULT_PROPERTIES, loadedSources);
} }
else { else {
existingSources.addLast(configurationSources); existingSources.addLast(loadedSources);
} }
} }
@ -670,14 +670,14 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
* Holds the configuration {@link PropertySource}s as they are loaded can relocate * Holds the configuration {@link PropertySource}s as they are loaded can relocate
* them once configuration classes have been processed. * them once configuration classes have been processed.
*/ */
static class ConfigurationPropertySources static class LoadedPropertySources
extends EnumerablePropertySource<Collection<PropertySource<?>>> { extends EnumerablePropertySource<Collection<PropertySource<?>>> {
private final Collection<PropertySource<?>> sources; private final Collection<PropertySource<?>> sources;
private final String[] names; private final String[] names;
ConfigurationPropertySources(Collection<PropertySource<?>> sources) { LoadedPropertySources(Collection<PropertySource<?>> sources) {
super(APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME, sources); super(APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME, sources);
this.sources = sources; this.sources = sources;
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
@ -703,7 +703,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
public static void finishAndRelocate(MutablePropertySources propertySources) { public static void finishAndRelocate(MutablePropertySources propertySources) {
String name = APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME; String name = APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME;
ConfigurationPropertySources removed = (ConfigurationPropertySources) propertySources LoadedPropertySources removed = (LoadedPropertySources) propertySources
.get(name); .get(name);
if (removed != null) { if (removed != null) {
for (PropertySource<?> propertySource : removed.sources) { for (PropertySource<?> propertySource : removed.sources) {
@ -729,48 +729,4 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
/**
* Holder for {@code spring.profiles} properties.
*/
static final class SpringProfiles {
private List<String> active = new ArrayList<>();
private List<String> include = new ArrayList<>();
public List<String> getActive() {
return this.active;
}
public void setActive(List<String> active) {
this.active = active;
}
public List<String> getInclude() {
return this.include;
}
public void setInclude(List<String> include) {
this.include = include;
}
Set<Profile> getActiveProfiles() {
return asProfileSet(this.active);
}
Set<Profile> getIncludeProfiles() {
return asProfileSet(this.include);
}
private Set<Profile> asProfileSet(List<String> profileNames) {
List<Profile> profiles = new ArrayList<>();
for (String profileName : profileNames) {
profiles.add(new Profile(profileName));
}
Collections.reverse(profiles);
return new LinkedHashSet<>(profiles);
}
}
} }

@ -16,9 +16,9 @@
package org.springframework.boot.context.logging; package org.springframework.boot.context.logging;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -26,11 +26,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
@ -77,11 +78,15 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Madhura Bhave
* @since 2.0.0 * @since 2.0.0
* @see LoggingSystem#get(ClassLoader) * @see LoggingSystem#get(ClassLoader)
*/ */
public class LoggingApplicationListener implements GenericApplicationListener { public class LoggingApplicationListener implements GenericApplicationListener {
private static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable
.mapOf(String.class, String.class);
/** /**
* The default order for the LoggingApplicationListener. * The default order for the LoggingApplicationListener.
*/ */
@ -294,20 +299,18 @@ public class LoggingApplicationListener implements GenericApplicationListener {
} }
protected void setLogLevels(LoggingSystem system, Environment environment) { protected void setLogLevels(LoggingSystem system, Environment environment) {
Map<String, Object> levels = new RelaxedPropertyResolver(environment) if (!(environment instanceof ConfigurableEnvironment)) {
.getSubProperties("logging.level."); return;
for (Entry<String, Object> entry : levels.entrySet()) {
setLogLevel(system, environment, entry.getKey(), entry.getValue().toString());
} }
Binder binder = Binder.get(environment);
binder.bind("logging.level", STRING_STRING_MAP).orElseGet(Collections::emptyMap)
.forEach((name, level) -> setLogLevel(system, environment, name, level));
} }
private void setLogLevel(LoggingSystem system, Environment environment, String name, private void setLogLevel(LoggingSystem system, Environment environment, String name,
String level) { String level) {
try { try {
if (name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME)) { name = (name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME) ? null : name);
name = null;
}
level = environment.resolvePlaceholders(level);
system.setLogLevel(name, coerceLogLevel(level)); system.setLogLevel(name, coerceLogLevel(level));
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
@ -324,7 +327,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private void registerShutdownHookIfNecessary(Environment environment, private void registerShutdownHookIfNecessary(Environment environment,
LoggingSystem loggingSystem) { LoggingSystem loggingSystem) {
boolean registerShutdownHook = new RelaxedPropertyResolver(environment) boolean registerShutdownHook = environment
.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, false); .getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, false);
if (registerShutdownHook) { if (registerShutdownHook) {
Runnable shutdownHandler = loggingSystem.getShutdownHandler(); Runnable shutdownHandler = loggingSystem.getShutdownHandler();

@ -17,7 +17,6 @@
package org.springframework.boot.context.properties; package org.springframework.boot.context.properties;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,7 +33,15 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
import org.springframework.boot.context.properties.bind.handler.IgnoreErrorsBindHandler;
import org.springframework.boot.context.properties.bind.handler.IgnoreNestedPropertiesBindHandler;
import org.springframework.boot.context.properties.bind.handler.NoUnboundElementsBindHandler;
import org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.validation.MessageInterpolatorFactory; import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
@ -53,13 +60,10 @@ import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySources;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
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.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -73,6 +77,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
* @author Phillip Webb * @author Phillip Webb
* @author Christian Dupuis * @author Christian Dupuis
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Madhura Bhave
*/ */
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean, BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean,
@ -113,6 +118,10 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
private int order = Ordered.HIGHEST_PRECEDENCE + 1; private int order = Ordered.HIGHEST_PRECEDENCE + 1;
private ConfigurationPropertySources configurationSources;
private Binder binder;
/** /**
* A list of custom converters (in addition to the defaults) to use when converting * A list of custom converters (in addition to the defaults) to use when converting
* properties for binding. * properties for binding.
@ -212,6 +221,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME, ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
ConversionService.class); ConversionService.class);
} }
this.configurationSources = ConfigurationPropertySources
.get(this.propertySources);
} }
@Override @Override
@ -240,18 +251,13 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
private PropertySources deducePropertySources() { private PropertySources deducePropertySources() {
PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer(); PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();
if (configurer != null) { if (configurer != null) {
// Flatten the sources into a single list so they can be iterated return configurer.getAppliedPropertySources();
return new FlatPropertySources(configurer.getAppliedPropertySources());
} }
if (this.environment instanceof ConfigurableEnvironment) { if (this.environment instanceof ConfigurableEnvironment) {
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment) return ((ConfigurableEnvironment) this.environment).getPropertySources();
.getPropertySources();
return new FlatPropertySources(propertySources);
} }
// empty, so not very useful, but fulfils the contract throw new IllegalStateException("Unable to obtain PropertySources from "
logger.warn("Unable to obtain PropertySources from "
+ "PropertySourcesPlaceholderConfigurer or Environment"); + "PropertySourcesPlaceholderConfigurer or Environment");
return new MutablePropertySources();
} }
private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() { private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {
@ -287,15 +293,16 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
throws BeansException { throws BeansException {
ConfigurationProperties annotation = AnnotationUtils ConfigurationProperties annotation = AnnotationUtils
.findAnnotation(bean.getClass(), ConfigurationProperties.class); .findAnnotation(bean.getClass(), ConfigurationProperties.class);
Object bound = bean;
if (annotation != null) { if (annotation != null) {
postProcessBeforeInitialization(bean, beanName, annotation); bound = postProcessBeforeInitialization(bean, beanName, annotation);
} }
annotation = this.beans.findFactoryAnnotation(beanName, annotation = this.beans.findFactoryAnnotation(beanName,
ConfigurationProperties.class); ConfigurationProperties.class);
if (annotation != null) { if (annotation != null) {
postProcessBeforeInitialization(bean, beanName, annotation); bound = postProcessBeforeInitialization(bean, beanName, annotation);
} }
return bean; return bound;
} }
@Override @Override
@ -304,35 +311,53 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
return bean; return bean;
} }
private void postProcessBeforeInitialization(Object bean, String beanName, private Object postProcessBeforeInitialization(Object bean, String beanName,
ConfigurationProperties annotation) { ConfigurationProperties annotation) {
Object target = bean; Binder binder = getBinder();
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<>( Validator validator = determineValidator(bean);
target); BindHandler handler = getBindHandler(annotation, validator);
factory.setPropertySources(this.propertySources); Bindable<?> bindable = Bindable.ofInstance(bean);
factory.setValidator(determineValidator(bean));
// If no explicit conversion service is provided we add one so that (at least)
// comma-separated arrays of convertibles can be bound automatically
factory.setConversionService(this.conversionService == null
? getDefaultConversionService() : this.conversionService);
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
if (StringUtils.hasLength(annotation.prefix())) {
factory.setTargetName(annotation.prefix());
}
}
try { try {
factory.bindPropertiesToTarget(); binder.bind(annotation.prefix(), bindable, handler);
return bean;
} }
catch (Exception ex) { catch (Exception ex) {
String targetClass = ClassUtils.getShortName(target.getClass()); String targetClass = ClassUtils.getShortName(bean.getClass());
throw new BeanCreationException(beanName, "Could not bind properties to " throw new BeanCreationException(beanName, "Could not bind properties to "
+ targetClass + " (" + getAnnotationDetails(annotation) + ")", ex); + targetClass + " (" + getAnnotationDetails(annotation) + ")", ex);
} }
} }
private Binder getBinder() {
Binder binder = this.binder;
if (binder == null) {
ConversionService conversionService = this.conversionService;
if (conversionService == null) {
conversionService = getDefaultConversionService();
}
binder = new Binder(this.configurationSources,
new PropertySourcesPlaceholdersResolver(this.propertySources),
conversionService);
this.binder = binder;
}
return binder;
}
private ConversionService getDefaultConversionService() {
if (this.defaultConversionService == null) {
DefaultConversionService conversionService = new DefaultConversionService();
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(this);
for (Converter<?, ?> converter : this.converters) {
conversionService.addConverter(converter);
}
for (GenericConverter genericConverter : this.genericConverters) {
conversionService.addConverter(genericConverter);
}
this.defaultConversionService = conversionService;
}
return this.defaultConversionService;
}
private String getAnnotationDetails(ConfigurationProperties annotation) { private String getAnnotationDetails(ConfigurationProperties annotation) {
if (annotation == null) { if (annotation == null) {
return ""; return "";
@ -379,19 +404,22 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
return true; return true;
} }
private ConversionService getDefaultConversionService() { private BindHandler getBindHandler(ConfigurationProperties annotation,
if (this.defaultConversionService == null) { Validator validator) {
DefaultConversionService conversionService = new DefaultConversionService(); BindHandler handler = BindHandler.DEFAULT;
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(this); if (annotation.ignoreInvalidFields()) {
for (Converter<?, ?> converter : this.converters) { handler = new IgnoreErrorsBindHandler(handler);
conversionService.addConverter(converter);
} }
for (GenericConverter genericConverter : this.genericConverters) { if (!annotation.ignoreUnknownFields()) {
conversionService.addConverter(genericConverter); handler = new NoUnboundElementsBindHandler(handler);
} }
this.defaultConversionService = conversionService; if (annotation.ignoreNestedProperties()) {
handler = new IgnoreNestedPropertiesBindHandler(handler);
} }
return this.defaultConversionService; if (validator != null) {
handler = new ValidationBindHandler(handler, validator);
}
return handler;
} }
/** /**
@ -465,56 +493,4 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
} }
/**
* Convenience class to flatten out a tree of property sources without losing the
* reference to the backing data (which can therefore be updated in the background).
*/
private static class FlatPropertySources implements PropertySources {
private PropertySources propertySources;
FlatPropertySources(PropertySources propertySources) {
this.propertySources = propertySources;
}
@Override
public Iterator<PropertySource<?>> iterator() {
MutablePropertySources result = getFlattened();
return result.iterator();
}
@Override
public boolean contains(String name) {
return get(name) != null;
}
@Override
public PropertySource<?> get(String name) {
return getFlattened().get(name);
}
private MutablePropertySources getFlattened() {
MutablePropertySources result = new MutablePropertySources();
for (PropertySource<?> propertySource : this.propertySources) {
flattenPropertySources(propertySource, result);
}
return result;
}
private void flattenPropertySources(PropertySource<?> propertySource,
MutablePropertySources result) {
Object source = propertySource.getSource();
if (source instanceof ConfigurableEnvironment) {
ConfigurableEnvironment environment = (ConfigurableEnvironment) source;
for (PropertySource<?> childSource : environment.getPropertySources()) {
flattenPropertySources(childSource, result);
}
}
else {
result.addLast(propertySource);
}
}
}
} }

@ -17,8 +17,10 @@
package org.springframework.boot.logging; package org.springframework.boot.logging;
import org.springframework.boot.ApplicationPid; import org.springframework.boot.ApplicationPid;
import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -26,6 +28,7 @@ import org.springframework.util.Assert;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Phillip Webb * @author Phillip Webb
* @author Madhura Bhave
* @since 2.0.0 * @since 2.0.0
*/ */
public class LoggingSystemProperties { public class LoggingSystemProperties {
@ -81,22 +84,33 @@ public class LoggingSystemProperties {
} }
public void apply(LogFile logFile) { public void apply(LogFile logFile) {
RelaxedPropertyResolver propertyResolver = RelaxedPropertyResolver PropertyResolver resolver = getPropertyResolver();
.ignoringUnresolvableNestedPlaceholders(this.environment, "logging."); setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD,
setSystemProperty(propertyResolver, EXCEPTION_CONVERSION_WORD,
"exception-conversion-word"); "exception-conversion-word");
setSystemProperty(propertyResolver, CONSOLE_LOG_PATTERN, "pattern.console"); setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "pattern.console");
setSystemProperty(propertyResolver, FILE_LOG_PATTERN, "pattern.file"); setSystemProperty(resolver, FILE_LOG_PATTERN, "pattern.file");
setSystemProperty(propertyResolver, LOG_LEVEL_PATTERN, "pattern.level"); setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level");
setSystemProperty(PID_KEY, new ApplicationPid().toString()); setSystemProperty(PID_KEY, new ApplicationPid().toString());
if (logFile != null) { if (logFile != null) {
logFile.applyToSystemProperties(); logFile.applyToSystemProperties();
} }
} }
private void setSystemProperty(RelaxedPropertyResolver propertyResolver, private PropertyResolver getPropertyResolver() {
String systemPropertyName, String propertyName) { if (this.environment instanceof ConfigurableEnvironment) {
setSystemProperty(systemPropertyName, propertyResolver.getProperty(propertyName)); PropertyResolver resolver = new PropertySourcesPropertyResolver(
((ConfigurableEnvironment) this.environment).getPropertySources());
((PropertySourcesPropertyResolver) resolver)
.setIgnoreUnresolvableNestedPlaceholders(true);
return resolver;
}
return this.environment;
}
private void setSystemProperty(PropertyResolver resolver, String systemPropertyName,
String propertyName) {
setSystemProperty(systemPropertyName,
resolver.getProperty("logging." + propertyName));
} }
private void setSystemProperty(String name, String value) { private void setSystemProperty(String name, String value) {

@ -30,9 +30,9 @@ import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.FileSize; import ch.qos.logback.core.util.FileSize;
import ch.qos.logback.core.util.OptionHelper; import ch.qos.logback.core.util.OptionHelper;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySourcesPropertyResolver; import org.springframework.core.env.PropertySourcesPropertyResolver;
@ -44,6 +44,7 @@ import org.springframework.util.ReflectionUtils;
* and {@code file-appender.xml} files provided for classic {@code logback.xml} use. * and {@code file-appender.xml} files provided for classic {@code logback.xml} use.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Madhura Bhave
* @since 1.1.2 * @since 1.1.2
*/ */
class DefaultLogbackConfiguration { class DefaultLogbackConfiguration {
@ -72,8 +73,13 @@ class DefaultLogbackConfiguration {
if (environment == null) { if (environment == null) {
return new PropertySourcesPropertyResolver(null); return new PropertySourcesPropertyResolver(null);
} }
return RelaxedPropertyResolver.ignoringUnresolvableNestedPlaceholders(environment, if (environment instanceof ConfigurableEnvironment) {
"logging.pattern."); PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
((ConfigurableEnvironment) environment).getPropertySources());
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
return resolver;
}
return environment;
} }
public void apply(LogbackConfigurator config) { public void apply(LogbackConfigurator config) {
@ -113,7 +119,8 @@ class DefaultLogbackConfiguration {
private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) { private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>(); ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
PatternLayoutEncoder encoder = new PatternLayoutEncoder(); PatternLayoutEncoder encoder = new PatternLayoutEncoder();
String logPattern = this.patterns.getProperty("console", CONSOLE_LOG_PATTERN); String logPattern = this.patterns.getProperty("logging.pattern.console",
CONSOLE_LOG_PATTERN);
encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
encoder.setCharset(UTF8); encoder.setCharset(UTF8);
config.start(encoder); config.start(encoder);
@ -126,7 +133,8 @@ class DefaultLogbackConfiguration {
String logFile) { String logFile) {
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>(); RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
PatternLayoutEncoder encoder = new PatternLayoutEncoder(); PatternLayoutEncoder encoder = new PatternLayoutEncoder();
String logPattern = this.patterns.getProperty("file", FILE_LOG_PATTERN); String logPattern = this.patterns.getProperty("logging.pattern.file",
FILE_LOG_PATTERN);
encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext())); encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
appender.setEncoder(encoder); appender.setEncoder(encoder);
config.start(encoder); config.start(encoder);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,6 @@ import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.util.OptionHelper; import ch.qos.logback.core.util.OptionHelper;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
/** /**
@ -33,6 +32,7 @@ import org.springframework.core.env.Environment;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Madhura Bhave
*/ */
class SpringPropertyAction extends Action { class SpringPropertyAction extends Action {
@ -47,8 +47,8 @@ class SpringPropertyAction extends Action {
} }
@Override @Override
public void begin(InterpretationContext ic, String elementName, Attributes attributes) public void begin(InterpretationContext context, String elementName,
throws ActionException { Attributes attributes) throws ActionException {
String name = attributes.getValue(NAME_ATTRIBUTE); String name = attributes.getValue(NAME_ATTRIBUTE);
String source = attributes.getValue(SOURCE_ATTRIBUTE); String source = attributes.getValue(SOURCE_ATTRIBUTE);
Scope scope = ActionUtil.stringToScope(attributes.getValue(SCOPE_ATTRIBUTE)); Scope scope = ActionUtil.stringToScope(attributes.getValue(SCOPE_ATTRIBUTE));
@ -57,7 +57,7 @@ class SpringPropertyAction extends Action {
addError( addError(
"The \"name\" and \"source\" attributes of <springProperty> must be set"); "The \"name\" and \"source\" attributes of <springProperty> must be set");
} }
ActionUtil.setProperty(ic, name, getValue(source, defaultValue), scope); ActionUtil.setProperty(context, name, getValue(source, defaultValue), scope);
} }
private String getValue(String source, String defaultValue) { private String getValue(String source, String defaultValue) {
@ -72,15 +72,14 @@ class SpringPropertyAction extends Action {
int lastDot = source.lastIndexOf("."); int lastDot = source.lastIndexOf(".");
if (lastDot > 0) { if (lastDot > 0) {
String prefix = source.substring(0, lastDot + 1); String prefix = source.substring(0, lastDot + 1);
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( return this.environment.getProperty(prefix + source.substring(lastDot + 1),
this.environment, prefix); defaultValue);
return resolver.getProperty(source.substring(lastDot + 1), defaultValue);
} }
return defaultValue; return defaultValue;
} }
@Override @Override
public void end(InterpretationContext ic, String name) throws ActionException { public void end(InterpretationContext context, String name) throws ActionException {
} }
} }

@ -27,7 +27,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.boot.ApplicationPid; import org.springframework.boot.ApplicationPid;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
@ -57,6 +56,7 @@ import org.springframework.util.Assert;
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author Tomasz Przybyla * @author Tomasz Przybyla
* @author Madhura Bhave
* @since 1.4.0 * @since 1.4.0
*/ */
public class ApplicationPidFileWriter public class ApplicationPidFileWriter
@ -221,8 +221,7 @@ public class ApplicationPidFileWriter
if (environment == null) { if (environment == null) {
return null; return null;
} }
return new RelaxedPropertyResolver(environment, this.prefix) return environment.getProperty(this.prefix + this.key);
.getProperty(this.key);
} }
private Environment getEnvironment(SpringApplicationEvent event) { private Environment getEnvironment(SpringApplicationEvent event) {

@ -25,14 +25,12 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher; import org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher;
import org.springframework.beans.factory.config.YamlProcessor.MatchStatus; import org.springframework.beans.factory.config.YamlProcessor.MatchStatus;
import org.springframework.boot.bind.PropertySourcesPropertyValues; import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.bind.RelaxedDataBinder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -47,6 +45,7 @@ import org.springframework.util.StringUtils;
* @author Matt Benson * @author Matt Benson
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Madhura Bhave
*/ */
public class SpringProfileDocumentMatcher implements DocumentMatcher { public class SpringProfileDocumentMatcher implements DocumentMatcher {
@ -69,14 +68,9 @@ public class SpringProfileDocumentMatcher implements DocumentMatcher {
} }
protected List<String> extractSpringProfiles(Properties properties) { protected List<String> extractSpringProfiles(Properties properties) {
SpringProperties springProperties = new SpringProperties(); Binder binder = new Binder(new MapConfigurationPropertySource(properties));
MutablePropertySources propertySources = new MutablePropertySources(); return binder.bind("spring.profiles", Bindable.of(String[].class))
propertySources.addFirst(new PropertiesPropertySource("profiles", properties)); .map(Arrays::asList).orElse(Collections.emptyList());
PropertyValues propertyValues = new PropertySourcesPropertyValues(
propertySources);
new RelaxedDataBinder(springProperties, "spring").bind(propertyValues);
List<String> profiles = springProperties.getProfiles();
return profiles;
} }
private MatchStatus matches(List<String> profiles) { private MatchStatus matches(List<String> profiles) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
@ -43,6 +44,7 @@ public class FileEncodingApplicationListenerTests {
public void testIllegalState() { public void testIllegalState() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.mandatory_file_encoding=FOO"); "spring.mandatory_file_encoding=FOO");
ConfigurationPropertySources.attach(this.environment);
this.initializer.onApplicationEvent(this.event); this.initializer.onApplicationEvent(this.event);
} }

@ -40,7 +40,7 @@ import org.junit.rules.ExpectedException;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType; import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.config.ConfigFileApplicationListener.ConfigurationPropertySources; import org.springframework.boot.context.config.ConfigFileApplicationListener.LoadedPropertySources;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.env.EnumerableCompositePropertySource; import org.springframework.boot.env.EnumerableCompositePropertySource;
@ -512,7 +512,7 @@ public class ConfigFileApplicationListenerTests {
String property = this.environment.getProperty("my.property"); String property = this.environment.getProperty("my.property");
assertThat(this.environment.getActiveProfiles()).contains("dev"); assertThat(this.environment.getActiveProfiles()).contains("dev");
assertThat(property).isEqualTo("fromdevprofile"); assertThat(property).isEqualTo("fromdevprofile");
ConfigurationPropertySources propertySource = (ConfigurationPropertySources) this.environment LoadedPropertySources propertySource = (LoadedPropertySources) this.environment
.getPropertySources() .getPropertySources()
.get(ConfigFileApplicationListener.APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME); .get(ConfigFileApplicationListener.APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME);
Collection<org.springframework.core.env.PropertySource<?>> sources = propertySource Collection<org.springframework.core.env.PropertySource<?>> sources = propertySource
@ -848,7 +848,7 @@ public class ConfigFileApplicationListenerTests {
public boolean matches(ConfigurableEnvironment value) { public boolean matches(ConfigurableEnvironment value) {
MutablePropertySources sources = new MutablePropertySources( MutablePropertySources sources = new MutablePropertySources(
value.getPropertySources()); value.getPropertySources());
ConfigurationPropertySources.finishAndRelocate(sources); LoadedPropertySources.finishAndRelocate(sources);
return sources.contains(sourceName); return sources.contains(sourceName);
} }

@ -41,6 +41,7 @@ import org.springframework.boot.ApplicationPid;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.junit.runner.classpath.ClassPathExclusions; import org.springframework.boot.junit.runner.classpath.ClassPathExclusions;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner; import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
import org.springframework.boot.logging.AbstractLoggingSystem; import org.springframework.boot.logging.AbstractLoggingSystem;
@ -56,6 +57,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
@ -72,7 +74,6 @@ import static org.hamcrest.Matchers.not;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Ben Hale * @author Ben Hale
*/ */
@RunWith(ModifiedClassPathRunner.class) @RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("log4j*.jar") @ClassPathExclusions("log4j*.jar")
public class LoggingApplicationListenerTests { public class LoggingApplicationListenerTests {
@ -103,6 +104,8 @@ public class LoggingApplicationListenerTests {
multicastEvent(new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); multicastEvent(new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
new File("target/foo.log").delete(); new File("target/foo.log").delete();
new File(tmpDir() + "/spring.log").delete(); new File(tmpDir() + "/spring.log").delete();
ConfigurableEnvironment environment = this.context.getEnvironment();
ConfigurationPropertySources.attach(environment.getPropertySources());
} }
@After @After

@ -34,7 +34,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.bind.RelaxedBindingNotWritablePropertyException; import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.boot.context.properties.bind.validation.BindValidationException;
import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -43,7 +44,6 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils; import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
@ -59,6 +59,7 @@ import static org.junit.Assert.fail;
* @author Christian Dupuis * @author Christian Dupuis
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Madhura Bhave
*/ */
public class ConfigurationPropertiesBindingPostProcessorTests { public class ConfigurationPropertiesBindingPostProcessorTests {
@ -83,7 +84,16 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"test.foo=spam"); "test.foo=spam");
this.context.register(TestConfigurationWithValidatingSetter.class); this.context.register(TestConfigurationWithValidatingSetter.class);
assertBindingFailure(1); try {
this.context.refresh();
fail("Expected exception");
}
catch (BeanCreationException ex) {
BindException bindException = (BindException) ex.getCause();
assertThat(bindException.getMessage())
.startsWith("Failed to bind properties under 'test' to "
+ PropertyWithValidatingSetter.class.getName());
}
} }
@Test @Test
@ -97,12 +107,9 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
fail("Expected exception"); fail("Expected exception");
} }
catch (BeanCreationException ex) { catch (BeanCreationException ex) {
RelaxedBindingNotWritablePropertyException bex = (RelaxedBindingNotWritablePropertyException) ex BindException bindException = (BindException) ex.getCause();
.getRootCause(); assertThat(bindException.getMessage())
assertThat(bex.getMessage()) .startsWith("Failed to bind properties under 'com.example' to "
.startsWith("Failed to bind 'com.example.baz' from '"
+ TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME
+ "' to 'baz' " + "property on '"
+ TestConfiguration.class.getName()); + TestConfiguration.class.getName());
} }
} }
@ -190,9 +197,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Test @Test
public void testRelaxedPropertyWithEnum() throws Exception { public void testRelaxedPropertyWithEnum() throws Exception {
doEnumTest("test.the-value=FoO"); doEnumTest("test.the-value=FoO");
doEnumTest("TEST_THE_VALUE=FoO");
doEnumTest("test.THE_VALUE=FoO"); doEnumTest("test.THE_VALUE=FoO");
doEnumTest("test_the_value=FoO");
} }
private void doEnumTest(String property) { private void doEnumTest(String property) {
@ -209,8 +214,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
public void testRelaxedPropertyWithSetOfEnum() { public void testRelaxedPropertyWithSetOfEnum() {
doEnumSetTest("test.the-values=foo,bar", FooEnum.FOO, FooEnum.BAR); doEnumSetTest("test.the-values=foo,bar", FooEnum.FOO, FooEnum.BAR);
doEnumSetTest("test.the-values=foo", FooEnum.FOO); doEnumSetTest("test.the-values=foo", FooEnum.FOO);
doEnumSetTest("TEST_THE_VALUES=FoO", FooEnum.FOO);
doEnumSetTest("test_the_values=BaR,FoO", FooEnum.BAR, FooEnum.FOO);
} }
private void doEnumSetTest(String property, FooEnum... expected) { private void doEnumSetTest(String property, FooEnum... expected) {
@ -266,17 +269,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
.isEqualTo("word".toCharArray()); .isEqualTo("word".toCharArray());
} }
@Test
public void configurationPropertiesWithArrayExpansion() throws Exception {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"test.chars[4]=s");
this.context.register(PropertyWithCharArrayExpansion.class);
this.context.refresh();
assertThat(this.context.getBean(PropertyWithCharArrayExpansion.class).getChars())
.isEqualTo("words".toCharArray());
}
@Test @Test
public void notWritablePropertyException() throws Exception { public void notWritablePropertyException() throws Exception {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
@ -294,12 +286,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
"test.BAR-B-A-Z=testa", "test.BAR-B-A-Z=testb"); "test.BAR-B-A-Z=testa", "test.BAR-B-A-Z=testb");
} }
@Test
public void relaxedPropertyNamesMixed() throws Exception {
testRelaxedPropertyNames("test.FOO_BAR=test2", "test.foo-bar=test1",
"test.BAR-B-A-Z=testb", "test.bar_b_a_z=testa");
}
private void testRelaxedPropertyNames(String... environment) { private void testRelaxedPropertyNames(String... environment) {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@ -316,7 +302,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
// gh-3539 // gh-3539
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"TEST_NESTED_VALUE=test1"); "test.nested.value=test1");
this.context.register(PropertyWithNestedValue.class); this.context.register(PropertyWithNestedValue.class);
this.context.refresh(); this.context.refresh();
assertThat(this.context.getBean(PropertyWithNestedValue.class).getNested() assertThat(this.context.getBean(PropertyWithNestedValue.class).getNested()
@ -335,6 +321,27 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
this.context.refresh(); this.context.refresh();
} }
@Test
public void bindWithIgnoreInvalidFieldsAnnotation() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"com.example.bar=spam");
this.context.register(TestConfigurationWithIgnoreErrors.class);
this.context.refresh();
assertThat(this.context.getBean(TestConfigurationWithIgnoreErrors.class).getBar())
.isEqualTo(0);
}
@Test
public void bindWithNoIgnoreInvalidFieldsAnnotation() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"com.example.foo=hello");
this.context.register(TestConfiguration.class);
this.thrown.expect(BeanCreationException.class);
this.context.refresh();
}
@Test @Test
public void multiplePropertySourcesPlaceholderConfigurer() throws Exception { public void multiplePropertySourcesPlaceholderConfigurer() throws Exception {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
@ -361,8 +368,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
fail("Expected exception"); fail("Expected exception");
} }
catch (BeanCreationException ex) { catch (BeanCreationException ex) {
BindException bex = (BindException) ex.getRootCause(); assertThat(((BindValidationException) ex.getRootCause()).getValidationErrors()
assertThat(bex.getErrorCount()).isEqualTo(errorCount); .getAllErrors().size()).isEqualTo(errorCount);
} }
} }
@ -407,6 +414,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
} }
@ConfigurationProperties(prefix = "test") @ConfigurationProperties(prefix = "test")
@Validated
public static class PropertyWithoutJSR303 implements Validator { public static class PropertyWithoutJSR303 implements Validator {
private String foo; private String foo;
@ -469,6 +477,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@ConfigurationProperties(prefix = "com.example", ignoreUnknownFields = false) @ConfigurationProperties(prefix = "com.example", ignoreUnknownFields = false)
public static class TestConfiguration { public static class TestConfiguration {
private int foo;
private String bar; private String bar;
public void setBar(String bar) { public void setBar(String bar) {
@ -479,6 +489,30 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
return this.bar; return this.bar;
} }
public int getFoo() {
return this.foo;
}
public void setFoo(int foo) {
this.foo = foo;
}
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "com.example", ignoreInvalidFields = true)
public static class TestConfigurationWithIgnoreErrors {
private long bar;
public void setBar(long bar) {
this.bar = bar;
}
public long getBar() {
return this.bar;
}
} }
@ConfigurationProperties(prefix = "test") @ConfigurationProperties(prefix = "test")
@ -549,6 +583,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
} }
@ConfigurationProperties(prefix = "custom") @ConfigurationProperties(prefix = "custom")
@Validated
public static class PropertyWithCustomValidator { public static class PropertyWithCustomValidator {
private String foo; private String foo;
@ -647,6 +682,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@ConfigurationProperties(prefix = "test") @ConfigurationProperties(prefix = "test")
@Validated
public static class PropertyWithValue { public static class PropertyWithValue {
@Value("${default.value}") @Value("${default.value}")
@ -669,6 +705,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@Validated
@ConfigurationProperties(prefix = "test") @ConfigurationProperties(prefix = "test")
public static class PropertiesWithMap { public static class PropertiesWithMap {

@ -30,6 +30,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -37,7 +38,6 @@ import org.springframework.context.annotation.ImportResource;
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Dave Syer * @author Dave Syer
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Madhura Bhave
*/ */
public class EnableConfigurationPropertiesTests { public class EnableConfigurationPropertiesTests {
@ -94,30 +95,6 @@ public class EnableConfigurationPropertiesTests {
.isEqualTo("bar"); .isEqualTo("bar");
} }
@Test
public void testNestedSystemPropertiesBindingWithUnderscore() {
this.context.register(NestedConfiguration.class);
System.setProperty("name", "foo");
System.setProperty("nested_name", "bar");
this.context.refresh();
assertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);
assertThat(this.context.getBean(NestedProperties.class).name).isEqualTo("foo");
assertThat(this.context.getBean(NestedProperties.class).nested.name)
.isEqualTo("bar");
}
@Test
public void testNestedOsEnvironmentVariableWithUnderscore() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"NAME=foo", "NESTED_NAME=bar");
this.context.register(NestedConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);
assertThat(this.context.getBean(NestedProperties.class).name).isEqualTo("foo");
assertThat(this.context.getBean(NestedProperties.class).nested.name)
.isEqualTo("bar");
}
@Test @Test
public void testStrictPropertiesBinding() { public void testStrictPropertiesBinding() {
removeSystemProperties(); removeSystemProperties();
@ -134,18 +111,7 @@ public class EnableConfigurationPropertiesTests {
public void testPropertiesEmbeddedBinding() { public void testPropertiesEmbeddedBinding() {
this.context.register(EmbeddedTestConfiguration.class); this.context.register(EmbeddedTestConfiguration.class);
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"spring_foo_name=foo"); "spring.foo.name=foo");
this.context.refresh();
assertThat(this.context.getBeanNamesForType(EmbeddedTestProperties.class))
.hasSize(1);
assertThat(this.context.getBean(TestProperties.class).name).isEqualTo("foo");
}
@Test
public void testOsEnvironmentVariableEmbeddedBinding() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"SPRING_FOO_NAME=foo");
this.context.register(EmbeddedTestConfiguration.class);
this.context.refresh(); this.context.refresh();
assertThat(this.context.getBeanNamesForType(EmbeddedTestProperties.class)) assertThat(this.context.getBeanNamesForType(EmbeddedTestProperties.class))
.hasSize(1); .hasSize(1);
@ -322,15 +288,6 @@ public class EnableConfigurationPropertiesTests {
assertThat(this.context.getBean(TestConsumer.class).getName()).isEqualTo("foo"); assertThat(this.context.getBean(TestConsumer.class).getName()).isEqualTo("foo");
} }
@Test
public void testUnderscoresInPrefix() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"spring_test_external_val=baz");
this.context.register(SystemExampleConfig.class);
this.context.refresh();
assertThat(this.context.getBean(SystemEnvVar.class).getVal()).isEqualTo("baz");
}
@Test @Test
public void testSimpleAutoConfig() throws Exception { public void testSimpleAutoConfig() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@ -623,7 +580,7 @@ public class EnableConfigurationPropertiesTests {
private int[] array; private int[] array;
private final List<Integer> list = new ArrayList<>(); private List<Integer> list = new ArrayList<>();
// No getter - you should be able to bind to a write-only bean // No getter - you should be able to bind to a write-only bean
@ -643,6 +600,10 @@ public class EnableConfigurationPropertiesTests {
return this.list; return this.list;
} }
public void setList(List<Integer> list) {
this.list = list;
}
} }
@ConfigurationProperties(ignoreUnknownFields = false) @ConfigurationProperties(ignoreUnknownFields = false)

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder; import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
@ -139,6 +140,7 @@ public class SpringBootJoranConfiguratorTests {
public void relaxedSpringProperty() throws Exception { public void relaxedSpringProperty() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"my.EXAMPLE_PROPERTY=test"); "my.EXAMPLE_PROPERTY=test");
ConfigurationPropertySources.attach(this.environment);
initialize("property.xml"); initialize("property.xml");
assertThat(this.context.getProperty("MINE")).isEqualTo("test"); assertThat(this.context.getProperty("MINE")).isEqualTo("test");
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ public class SpringProfileDocumentMatcherTests {
@Test @Test
public void matchesSingleProfile() throws IOException { public void matchesSingleProfile() throws IOException {
DocumentMatcher matcher = new SpringProfileDocumentMatcher("foo", "bar"); DocumentMatcher matcher = new SpringProfileDocumentMatcher("foo", "bar");
Properties properties = getProperties("spring.profiles: foo"); Properties properties = getProperties("spring.ProfILEs: foo");
assertThat(matcher.matches(properties)).isEqualTo(MatchStatus.FOUND); assertThat(matcher.matches(properties)).isEqualTo(MatchStatus.FOUND);
} }

Loading…
Cancel
Save