diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java b/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java index cb41a2268b8..8a160634bec 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java @@ -86,6 +86,8 @@ public class PropertiesConfigurationFactory private ConversionService conversionService; + private boolean resolvePlaceholders = true; + /** * Create a new {@link PropertiesConfigurationFactory} instance. * @param target the target object to bind too @@ -203,6 +205,16 @@ public class PropertiesConfigurationFactory this.exceptionIfInvalid = exceptionIfInvalid; } + /** + * Flag to indicate that placeholders should be replaced during binding. Default is + * true. + * + * @param resolvePlaceholders flag value + */ + public void setResolvePlaceholders(boolean resolvePlaceholders) { + this.resolvePlaceholders = resolvePlaceholders; + } + @Override public void afterPropertiesSet() throws Exception { bindPropertiesToTarget(); @@ -322,7 +334,8 @@ public class PropertiesConfigurationFactory Iterable relaxedTargetNames) { PropertyNamePatternsMatcher includes = getPropertyNamePatternsMatcher(names, relaxedTargetNames); - return new PropertySourcesPropertyValues(this.propertySources, names, includes); + return new PropertySourcesPropertyValues(this.propertySources, names, includes, + this.resolvePlaceholders); } private PropertyNamePatternsMatcher getPropertyNamePatternsMatcher(Set names, diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java index 132ba8bd2d2..b385233f023 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java @@ -56,12 +56,15 @@ public class PropertySourcesPropertyValues implements PropertyValues { private final ConcurrentHashMap> collectionOwners = new ConcurrentHashMap>(); + private boolean resolvePlaceholders = true; + /** * Create a new PropertyValues from the given PropertySources. * @param propertySources a PropertySources instance */ public PropertySourcesPropertyValues(PropertySources propertySources) { - this(propertySources, (Collection) null, PropertyNamePatternsMatcher.ALL); + this(propertySources, (Collection) null, PropertyNamePatternsMatcher.ALL, + true); } /** @@ -76,7 +79,7 @@ public class PropertySourcesPropertyValues implements PropertyValues { Collection includePatterns, Collection nonEnumerableFallbackNames) { this(propertySources, nonEnumerableFallbackNames, - new PatternPropertyNamePatternsMatcher(includePatterns)); + new PatternPropertyNamePatternsMatcher(includePatterns), true); } /** @@ -85,15 +88,17 @@ public class PropertySourcesPropertyValues implements PropertyValues { * @param nonEnumerableFallbackNames the property names to try in lieu of an * {@link EnumerablePropertySource}. * @param includes the property name patterns to include + * @param resolvePlaceholders flag to indicate the placeholders should be resolved */ PropertySourcesPropertyValues(PropertySources propertySources, Collection nonEnumerableFallbackNames, - PropertyNamePatternsMatcher includes) { + PropertyNamePatternsMatcher includes, boolean resolvePlaceholders) { Assert.notNull(propertySources, "PropertySources must not be null"); Assert.notNull(includes, "Includes must not be null"); this.propertySources = propertySources; this.nonEnumerableFallbackNames = nonEnumerableFallbackNames; this.includes = includes; + this.resolvePlaceholders = resolvePlaceholders; PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver( propertySources); for (PropertySource source : propertySources) { @@ -101,6 +106,16 @@ public class PropertySourcesPropertyValues implements PropertyValues { } } + /** + * Flag to indicate that placeholders should be replaced during binding. Default is + * true. + * + * @param resolvePlaceholders flag value + */ + public void setResolvePlaceholders(boolean resolvePlaceholders) { + this.resolvePlaceholders = resolvePlaceholders; + } + private void processPropertySource(PropertySource source, PropertySourcesPropertyResolver resolver) { if (source instanceof CompositePropertySource) { @@ -138,12 +153,14 @@ public class PropertySourcesPropertyValues implements PropertyValues { private Object getEnumerableProperty(EnumerablePropertySource source, PropertySourcesPropertyResolver resolver, String propertyName) { try { - return resolver.getProperty(propertyName, Object.class); + if (this.resolvePlaceholders) { + return resolver.getProperty(propertyName, Object.class); + } } catch (RuntimeException ex) { // Probably could not resolve placeholders, ignore it here - return source.getProperty(propertyName); } + return source.getProperty(propertyName); } private void processNonEnumerablePropertySource(PropertySource source, diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java index ac999c4acae..9a669cec6a3 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java @@ -105,6 +105,35 @@ public class PropertiesConfigurationFactoryTests { assertThat(foo.name).isEqualTo("bar"); } + @Test + public void systemEnvironmentBindingWithDefaults() throws Exception { + setupFactory(); + MutablePropertySources propertySources = new MutablePropertySources(); + MockPropertySource propertySource = new MockPropertySource( + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + propertySource.setProperty("name", "${foo.name:bar}"); + propertySources.addFirst(propertySource); + this.factory.setPropertySources(propertySources); + this.factory.afterPropertiesSet(); + Foo foo = this.factory.getObject(); + assertThat(foo.name).isEqualTo("bar"); + } + + @Test + public void systemEnvironmentNoResolvePlaceholders() throws Exception { + setupFactory(); + MutablePropertySources propertySources = new MutablePropertySources(); + MockPropertySource propertySource = new MockPropertySource( + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + propertySource.setProperty("name", "${foo.name:bar}"); + propertySources.addFirst(propertySource); + this.factory.setPropertySources(propertySources); + this.factory.setResolvePlaceholders(false); + this.factory.afterPropertiesSet(); + Foo foo = this.factory.getObject(); + assertThat(foo.name).isEqualTo("${foo.name:bar}"); + } + @Test public void systemPropertyBindingFailuresAreIgnored() throws Exception { setupFactory();