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");
* 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.AnsiElement;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
@ -45,6 +43,7 @@ import org.springframework.util.Assert;
*
* @author Craig Burke
* @author Phillip Webb
* @author Madhura Bhave
* @since 1.4.0
*/
public class ImageBanner implements Banner {
@ -92,12 +91,11 @@ public class ImageBanner implements Banner {
private void printBanner(Environment environment, PrintStream out)
throws IOException {
PropertyResolver properties = new RelaxedPropertyResolver(environment,
"banner.image.");
int width = properties.getProperty("width", Integer.class, 76);
int height = properties.getProperty("height", Integer.class, 0);
int margin = properties.getProperty("margin", Integer.class, 2);
boolean invert = properties.getProperty("invert", Boolean.class, false);
int width = environment.getProperty("banner.image.width", Integer.class, 76);
int height = environment.getProperty("banner.image.height", Integer.class, 0);
int margin = environment.getProperty("banner.image.margin", Integer.class, 2);
boolean invert = environment.getProperty("banner.image.invert", Boolean.class,
false);
BufferedImage image = readImage(width, height);
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.xml.XmlBeanDefinitionReader;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
@ -55,8 +55,6 @@ import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.GenericTypeResolver;
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.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
@ -76,7 +74,6 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StandardServletEnvironment;
@ -578,9 +575,8 @@ public class SpringApplication {
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(
CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
"spring.beaninfo.");
Boolean ignore = resolver.getProperty("ignore", Boolean.class, Boolean.TRUE);
Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
ignore.toString());
}
@ -591,16 +587,10 @@ public class SpringApplication {
* @param environment the environment to bind
*/
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 {
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);
}
}

@ -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");
* 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.LogFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* 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").
*
* @author Dave Syer
* @author Madhura Bhave
*/
public class FileEncodingApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
@ -56,11 +57,12 @@ public class FileEncodingApplicationListener
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
event.getEnvironment(), "spring.");
if (resolver.containsProperty("mandatoryFileEncoding")) {
ConfigurableEnvironment environment = event.getEnvironment();
if (!environment.containsProperty("spring.mandatory-file-encoding")) {
return;
}
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)) {
logger.error("System property 'file.encoding' is currently '" + encoding
+ "'. It should be '" + desired
@ -73,9 +75,7 @@ public class FileEncodingApplicationListener
+ desired + "'.");
throw new IllegalStateException(
"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");
* 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.Enabled;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* An {@link ApplicationListener} that configures {@link AnsiOutput} depending on the
@ -29,6 +30,7 @@ import org.springframework.core.Ordered;
* values.
*
* @author Raphael von der Grün
* @author Madhura Bhave
* @since 1.2.0
*/
public class AnsiOutputApplicationListener
@ -36,23 +38,17 @@ public class AnsiOutputApplicationListener
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
event.getEnvironment(), "spring.output.ansi.");
if (resolver.containsProperty("enabled")) {
String enabled = resolver.getProperty("enabled");
AnsiOutput.setEnabled(Enum.valueOf(Enabled.class, enabled.toUpperCase()));
}
if (resolver.containsProperty("console-available")) {
AnsiOutput.setConsoleAvailable(
resolver.getProperty("console-available", Boolean.class));
}
ConfigurableEnvironment environment = event.getEnvironment();
Binder.get(environment)
.bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class)
.ifBound(AnsiOutput::setEnabled);
AnsiOutput.setConsoleAvailable(environment
.getProperty("spring.output.ansi.console-available", Boolean.class));
}
@Override
public int getOrder() {
// Apply after ConfigFileApplicationListener has called all
// EnvironmentPostProcessors
// Apply after ConfigFileApplicationListener has called EnvironmentPostProcessors
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.ConfigurableListableBeanFactory;
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.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.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertySourcesLoader;
@ -90,6 +91,7 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Eddú Meléndez
* @author Madhura Bhave
*/
public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
ApplicationListener<ApplicationEvent>, Ordered {
@ -256,8 +258,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
}
private void reorderSources(ConfigurableEnvironment environment) {
ConfigurationPropertySources
.finishAndRelocate(environment.getPropertySources());
LoadedPropertySources.finishAndRelocate(environment.getPropertySources());
PropertySource<?> defaultProperties = environment.getPropertySources()
.remove(DEFAULT_PROPERTIES);
if (defaultProperties != null) {
@ -344,11 +345,11 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
}
// Any pre-existing active profiles set via property sources (e.g. System
// properties) take precedence over those added in config files.
SpringProfiles springProfiles = bindSpringProfiles(
this.environment.getPropertySources());
Set<Profile> activeProfiles = new LinkedHashSet<>(
springProfiles.getActiveProfiles());
activeProfiles.addAll(springProfiles.getIncludeProfiles());
Set<Profile> active = getProfiles(this.environment, "spring.profiles.active");
Set<Profile> activeProfiles = new LinkedHashSet<>(active);
Set<Profile> include = getProfiles(this.environment,
"spring.profiles.include");
activeProfiles.addAll(include);
maybeActivateProfiles(activeProfiles);
return activeProfiles;
}
@ -474,33 +475,34 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
}
private void handleProfileProperties(PropertySource<?> propertySource) {
SpringProfiles springProfiles = bindSpringProfiles(propertySource);
maybeActivateProfiles(springProfiles.getActiveProfiles());
addProfiles(springProfiles.getIncludeProfiles());
}
private SpringProfiles bindSpringProfiles(PropertySource<?> propertySource) {
MutablePropertySources propertySources = new MutablePropertySources();
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) {
SpringProfiles springProfiles = new SpringProfiles();
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,
"spring.profiles");
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));
springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
private Set<Profile> getProfiles(ConfigurableEnvironment environment,
String name) {
return getProfiles(environment.getPropertySources(), name);
}
private List<String> resolvePlaceholders(List<String> values) {
List<String> resolved = new ArrayList<>();
for (String value : values) {
resolved.add(this.environment.resolvePlaceholders(value));
private Set<Profile> getProfiles(PropertySources sources, String name) {
Binder binder = new Binder(ConfigurationPropertySources.get(sources),
new PropertySourcesPlaceholdersResolver(this.environment));
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) {
@ -601,19 +603,17 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
for (PropertySource<?> item : sources) {
reorderedSources.add(item);
}
addConfigurationProperties(
new ConfigurationPropertySources(reorderedSources));
addConfigurationProperties(new LoadedPropertySources(reorderedSources));
}
private void addConfigurationProperties(
ConfigurationPropertySources configurationSources) {
private void addConfigurationProperties(LoadedPropertySources loadedSources) {
MutablePropertySources existingSources = this.environment
.getPropertySources();
if (existingSources.contains(DEFAULT_PROPERTIES)) {
existingSources.addBefore(DEFAULT_PROPERTIES, configurationSources);
existingSources.addBefore(DEFAULT_PROPERTIES, loadedSources);
}
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
* them once configuration classes have been processed.
*/
static class ConfigurationPropertySources
static class LoadedPropertySources
extends EnumerablePropertySource<Collection<PropertySource<?>>> {
private final Collection<PropertySource<?>> sources;
private final String[] names;
ConfigurationPropertySources(Collection<PropertySource<?>> sources) {
LoadedPropertySources(Collection<PropertySource<?>> sources) {
super(APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME, sources);
this.sources = sources;
List<String> names = new ArrayList<>();
@ -703,7 +703,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
public static void finishAndRelocate(MutablePropertySources propertySources) {
String name = APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME;
ConfigurationPropertySources removed = (ConfigurationPropertySources) propertySources
LoadedPropertySources removed = (LoadedPropertySources) propertySources
.get(name);
if (removed != null) {
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;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
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.boot.SpringApplication;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
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.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
@ -77,11 +78,15 @@ import org.springframework.util.StringUtils;
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
* @author Madhura Bhave
* @since 2.0.0
* @see LoggingSystem#get(ClassLoader)
*/
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.
*/
@ -294,20 +299,18 @@ public class LoggingApplicationListener implements GenericApplicationListener {
}
protected void setLogLevels(LoggingSystem system, Environment environment) {
Map<String, Object> levels = new RelaxedPropertyResolver(environment)
.getSubProperties("logging.level.");
for (Entry<String, Object> entry : levels.entrySet()) {
setLogLevel(system, environment, entry.getKey(), entry.getValue().toString());
if (!(environment instanceof ConfigurableEnvironment)) {
return;
}
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,
String level) {
try {
if (name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME)) {
name = null;
}
level = environment.resolvePlaceholders(level);
name = (name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME) ? null : name);
system.setLogLevel(name, coerceLogLevel(level));
}
catch (RuntimeException ex) {
@ -324,7 +327,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private void registerShutdownHookIfNecessary(Environment environment,
LoggingSystem loggingSystem) {
boolean registerShutdownHook = new RelaxedPropertyResolver(environment)
boolean registerShutdownHook = environment
.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, false);
if (registerShutdownHook) {
Runnable shutdownHandler = loggingSystem.getShutdownHandler();

@ -17,7 +17,6 @@
package org.springframework.boot.context.properties;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
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.annotation.Autowired;
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.context.ApplicationContext;
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.env.ConfigurableEnvironment;
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.StandardEnvironment;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
@ -73,6 +77,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
* @author Phillip Webb
* @author Christian Dupuis
* @author Stephane Nicoll
* @author Madhura Bhave
*/
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean,
@ -113,6 +118,10 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
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
* properties for binding.
@ -212,6 +221,8 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
ConversionService.class);
}
this.configurationSources = ConfigurationPropertySources
.get(this.propertySources);
}
@Override
@ -240,18 +251,13 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
private PropertySources deducePropertySources() {
PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();
if (configurer != null) {
// Flatten the sources into a single list so they can be iterated
return new FlatPropertySources(configurer.getAppliedPropertySources());
return configurer.getAppliedPropertySources();
}
if (this.environment instanceof ConfigurableEnvironment) {
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment)
.getPropertySources();
return new FlatPropertySources(propertySources);
return ((ConfigurableEnvironment) this.environment).getPropertySources();
}
// empty, so not very useful, but fulfils the contract
logger.warn("Unable to obtain PropertySources from "
throw new IllegalStateException("Unable to obtain PropertySources from "
+ "PropertySourcesPlaceholderConfigurer or Environment");
return new MutablePropertySources();
}
private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {
@ -287,15 +293,16 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
throws BeansException {
ConfigurationProperties annotation = AnnotationUtils
.findAnnotation(bean.getClass(), ConfigurationProperties.class);
Object bound = bean;
if (annotation != null) {
postProcessBeforeInitialization(bean, beanName, annotation);
bound = postProcessBeforeInitialization(bean, beanName, annotation);
}
annotation = this.beans.findFactoryAnnotation(beanName,
ConfigurationProperties.class);
if (annotation != null) {
postProcessBeforeInitialization(bean, beanName, annotation);
bound = postProcessBeforeInitialization(bean, beanName, annotation);
}
return bean;
return bound;
}
@Override
@ -304,35 +311,53 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
return bean;
}
private void postProcessBeforeInitialization(Object bean, String beanName,
private Object postProcessBeforeInitialization(Object bean, String beanName,
ConfigurationProperties annotation) {
Object target = bean;
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<>(
target);
factory.setPropertySources(this.propertySources);
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());
}
}
Binder binder = getBinder();
Validator validator = determineValidator(bean);
BindHandler handler = getBindHandler(annotation, validator);
Bindable<?> bindable = Bindable.ofInstance(bean);
try {
factory.bindPropertiesToTarget();
binder.bind(annotation.prefix(), bindable, handler);
return bean;
}
catch (Exception ex) {
String targetClass = ClassUtils.getShortName(target.getClass());
String targetClass = ClassUtils.getShortName(bean.getClass());
throw new BeanCreationException(beanName, "Could not bind properties to "
+ 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) {
if (annotation == null) {
return "";
@ -379,19 +404,22 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
return true;
}
private ConversionService getDefaultConversionService() {
if (this.defaultConversionService == null) {
DefaultConversionService conversionService = new DefaultConversionService();
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(this);
for (Converter<?, ?> converter : this.converters) {
conversionService.addConverter(converter);
private BindHandler getBindHandler(ConfigurationProperties annotation,
Validator validator) {
BindHandler handler = BindHandler.DEFAULT;
if (annotation.ignoreInvalidFields()) {
handler = new IgnoreErrorsBindHandler(handler);
}
for (GenericConverter genericConverter : this.genericConverters) {
conversionService.addConverter(genericConverter);
if (!annotation.ignoreUnknownFields()) {
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;
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.PropertyResolver;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.util.Assert;
/**
@ -26,6 +28,7 @@ import org.springframework.util.Assert;
*
* @author Andy Wilkinson
* @author Phillip Webb
* @author Madhura Bhave
* @since 2.0.0
*/
public class LoggingSystemProperties {
@ -81,22 +84,33 @@ public class LoggingSystemProperties {
}
public void apply(LogFile logFile) {
RelaxedPropertyResolver propertyResolver = RelaxedPropertyResolver
.ignoringUnresolvableNestedPlaceholders(this.environment, "logging.");
setSystemProperty(propertyResolver, EXCEPTION_CONVERSION_WORD,
PropertyResolver resolver = getPropertyResolver();
setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD,
"exception-conversion-word");
setSystemProperty(propertyResolver, CONSOLE_LOG_PATTERN, "pattern.console");
setSystemProperty(propertyResolver, FILE_LOG_PATTERN, "pattern.file");
setSystemProperty(propertyResolver, LOG_LEVEL_PATTERN, "pattern.level");
setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "pattern.console");
setSystemProperty(resolver, FILE_LOG_PATTERN, "pattern.file");
setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level");
setSystemProperty(PID_KEY, new ApplicationPid().toString());
if (logFile != null) {
logFile.applyToSystemProperties();
}
}
private void setSystemProperty(RelaxedPropertyResolver propertyResolver,
String systemPropertyName, String propertyName) {
setSystemProperty(systemPropertyName, propertyResolver.getProperty(propertyName));
private PropertyResolver getPropertyResolver() {
if (this.environment instanceof ConfigurableEnvironment) {
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) {

@ -30,9 +30,9 @@ import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.FileSize;
import ch.qos.logback.core.util.OptionHelper;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
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.
*
* @author Phillip Webb
* @author Madhura Bhave
* @since 1.1.2
*/
class DefaultLogbackConfiguration {
@ -72,8 +73,13 @@ class DefaultLogbackConfiguration {
if (environment == null) {
return new PropertySourcesPropertyResolver(null);
}
return RelaxedPropertyResolver.ignoringUnresolvableNestedPlaceholders(environment,
"logging.pattern.");
if (environment instanceof ConfigurableEnvironment) {
PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
((ConfigurableEnvironment) environment).getPropertySources());
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
return resolver;
}
return environment;
}
public void apply(LogbackConfigurator config) {
@ -113,7 +119,8 @@ class DefaultLogbackConfiguration {
private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
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.setCharset(UTF8);
config.start(encoder);
@ -126,7 +133,8 @@ class DefaultLogbackConfiguration {
String logFile) {
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
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()));
appender.setEncoder(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");
* 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 org.xml.sax.Attributes;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.env.Environment;
/**
@ -33,6 +32,7 @@ import org.springframework.core.env.Environment;
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Madhura Bhave
*/
class SpringPropertyAction extends Action {
@ -47,8 +47,8 @@ class SpringPropertyAction extends Action {
}
@Override
public void begin(InterpretationContext ic, String elementName, Attributes attributes)
throws ActionException {
public void begin(InterpretationContext context, String elementName,
Attributes attributes) throws ActionException {
String name = attributes.getValue(NAME_ATTRIBUTE);
String source = attributes.getValue(SOURCE_ATTRIBUTE);
Scope scope = ActionUtil.stringToScope(attributes.getValue(SCOPE_ATTRIBUTE));
@ -57,7 +57,7 @@ class SpringPropertyAction extends Action {
addError(
"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) {
@ -72,15 +72,14 @@ class SpringPropertyAction extends Action {
int lastDot = source.lastIndexOf(".");
if (lastDot > 0) {
String prefix = source.substring(0, lastDot + 1);
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
this.environment, prefix);
return resolver.getProperty(source.substring(lastDot + 1), defaultValue);
return this.environment.getProperty(prefix + source.substring(lastDot + 1),
defaultValue);
}
return defaultValue;
}
@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.springframework.boot.ApplicationPid;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
@ -57,6 +56,7 @@ import org.springframework.util.Assert;
* @author Dave Syer
* @author Phillip Webb
* @author Tomasz Przybyla
* @author Madhura Bhave
* @since 1.4.0
*/
public class ApplicationPidFileWriter
@ -221,8 +221,7 @@ public class ApplicationPidFileWriter
if (environment == null) {
return null;
}
return new RelaxedPropertyResolver(environment, this.prefix)
.getProperty(this.key);
return environment.getProperty(this.prefix + this.key);
}
private Environment getEnvironment(SpringApplicationEvent event) {

@ -25,14 +25,12 @@ import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher;
import org.springframework.beans.factory.config.YamlProcessor.MatchStatus;
import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.context.properties.bind.Bindable;
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.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@ -47,6 +45,7 @@ import org.springframework.util.StringUtils;
* @author Matt Benson
* @author Phillip Webb
* @author Andy Wilkinson
* @author Madhura Bhave
*/
public class SpringProfileDocumentMatcher implements DocumentMatcher {
@ -69,14 +68,9 @@ public class SpringProfileDocumentMatcher implements DocumentMatcher {
}
protected List<String> extractSpringProfiles(Properties properties) {
SpringProperties springProperties = new SpringProperties();
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new PropertiesPropertySource("profiles", properties));
PropertyValues propertyValues = new PropertySourcesPropertyValues(
propertySources);
new RelaxedDataBinder(springProperties, "spring").bind(propertyValues);
List<String> profiles = springProperties.getProfiles();
return profiles;
Binder binder = new Binder(new MapConfigurationPropertySource(properties));
return binder.bind("spring.profiles", Bindable.of(String[].class))
.map(Arrays::asList).orElse(Collections.emptyList());
}
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");
* 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.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
@ -43,6 +44,7 @@ public class FileEncodingApplicationListenerTests {
public void testIllegalState() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.mandatory_file_encoding=FOO");
ConfigurationPropertySources.attach(this.environment);
this.initializer.onApplicationEvent(this.event);
}

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

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

@ -34,7 +34,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
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.context.annotation.AnnotationConfigApplicationContext;
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.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
@ -59,6 +59,7 @@ import static org.junit.Assert.fail;
* @author Christian Dupuis
* @author Phillip Webb
* @author Stephane Nicoll
* @author Madhura Bhave
*/
public class ConfigurationPropertiesBindingPostProcessorTests {
@ -83,7 +84,16 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"test.foo=spam");
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
@ -97,12 +107,9 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
fail("Expected exception");
}
catch (BeanCreationException ex) {
RelaxedBindingNotWritablePropertyException bex = (RelaxedBindingNotWritablePropertyException) ex
.getRootCause();
assertThat(bex.getMessage())
.startsWith("Failed to bind 'com.example.baz' from '"
+ TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME
+ "' to 'baz' " + "property on '"
BindException bindException = (BindException) ex.getCause();
assertThat(bindException.getMessage())
.startsWith("Failed to bind properties under 'com.example' to "
+ TestConfiguration.class.getName());
}
}
@ -190,9 +197,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Test
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");
}
private void doEnumTest(String property) {
@ -209,8 +214,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
public void testRelaxedPropertyWithSetOfEnum() {
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=BaR,FoO", FooEnum.BAR, FooEnum.FOO);
}
private void doEnumSetTest(String property, FooEnum... expected) {
@ -266,17 +269,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
.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
public void notWritablePropertyException() throws Exception {
this.context = new AnnotationConfigApplicationContext();
@ -294,12 +286,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
"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) {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@ -316,7 +302,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
// gh-3539
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"TEST_NESTED_VALUE=test1");
"test.nested.value=test1");
this.context.register(PropertyWithNestedValue.class);
this.context.refresh();
assertThat(this.context.getBean(PropertyWithNestedValue.class).getNested()
@ -335,6 +321,27 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
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
public void multiplePropertySourcesPlaceholderConfigurer() throws Exception {
this.context = new AnnotationConfigApplicationContext();
@ -361,8 +368,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
fail("Expected exception");
}
catch (BeanCreationException ex) {
BindException bex = (BindException) ex.getRootCause();
assertThat(bex.getErrorCount()).isEqualTo(errorCount);
assertThat(((BindValidationException) ex.getRootCause()).getValidationErrors()
.getAllErrors().size()).isEqualTo(errorCount);
}
}
@ -407,6 +414,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
}
@ConfigurationProperties(prefix = "test")
@Validated
public static class PropertyWithoutJSR303 implements Validator {
private String foo;
@ -469,6 +477,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@ConfigurationProperties(prefix = "com.example", ignoreUnknownFields = false)
public static class TestConfiguration {
private int foo;
private String bar;
public void setBar(String bar) {
@ -479,6 +489,30 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
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")
@ -549,6 +583,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
}
@ConfigurationProperties(prefix = "custom")
@Validated
public static class PropertyWithCustomValidator {
private String foo;
@ -647,6 +682,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "test")
@Validated
public static class PropertyWithValue {
@Value("${default.value}")
@ -669,6 +705,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
@Configuration
@EnableConfigurationProperties
@Validated
@ConfigurationProperties(prefix = "test")
public static class PropertiesWithMap {

@ -30,6 +30,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
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.Bean;
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.stereotype.Component;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.annotation.Validated;
import static org.assertj.core.api.Assertions.assertThat;
@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Madhura Bhave
*/
public class EnableConfigurationPropertiesTests {
@ -94,30 +95,6 @@ public class EnableConfigurationPropertiesTests {
.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
public void testStrictPropertiesBinding() {
removeSystemProperties();
@ -134,18 +111,7 @@ public class EnableConfigurationPropertiesTests {
public void testPropertiesEmbeddedBinding() {
this.context.register(EmbeddedTestConfiguration.class);
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"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);
"spring.foo.name=foo");
this.context.refresh();
assertThat(this.context.getBeanNamesForType(EmbeddedTestProperties.class))
.hasSize(1);
@ -322,15 +288,6 @@ public class EnableConfigurationPropertiesTests {
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
public void testSimpleAutoConfig() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
@ -623,7 +580,7 @@ public class EnableConfigurationPropertiesTests {
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
@ -643,6 +600,10 @@ public class EnableConfigurationPropertiesTests {
return this.list;
}
public void setList(List<Integer> list) {
this.list = list;
}
}
@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");
* 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.impl.StaticLoggerBinder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.mock.env.MockEnvironment;
@ -139,6 +140,7 @@ public class SpringBootJoranConfiguratorTests {
public void relaxedSpringProperty() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"my.EXAMPLE_PROPERTY=test");
ConfigurationPropertySources.attach(this.environment);
initialize("property.xml");
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");
* you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ public class SpringProfileDocumentMatcherTests {
@Test
public void matchesSingleProfile() throws IOException {
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);
}

Loading…
Cancel
Save