From eb045f1da13083cf2cd6f4d45184c252969be76c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 26 Sep 2017 18:16:45 +0200 Subject: [PATCH] Fix value of property in PropertySource descriptor Prior to this commit, if a key was present in multiple PropertySources, all descriptors shared the same common value. This commit makes sure that each PropertySource descriptor shows the value it defines rather than the one that is promoted in the Environment. Closes gh-10428 --- .../boot/actuate/env/EnvironmentEndpoint.java | 50 +++++++++---------- .../actuate/env/EnvironmentEndpointTests.java | 2 + .../PropertySourcesPlaceholdersResolver.java | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java index c7f67fc869b..0c95198d432 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java @@ -31,19 +31,20 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor; import org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor; +import org.springframework.boot.context.properties.bind.PlaceholdersResolver; +import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver; import org.springframework.boot.origin.OriginLookup; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; -import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertySource; -import org.springframework.core.env.PropertySources; -import org.springframework.core.env.PropertySourcesPropertyResolver; import org.springframework.core.env.StandardEnvironment; import org.springframework.http.HttpStatus; +import org.springframework.util.PropertyPlaceholderHelper; import org.springframework.util.StringUtils; +import org.springframework.util.SystemPropertyUtils; import org.springframework.web.bind.annotation.ResponseStatus; /** @@ -85,7 +86,7 @@ public class EnvironmentEndpoint { private EnvironmentDescriptor getEnvironmentDescriptor( Predicate propertyNamePredicate) { - PropertyResolver resolver = getResolver(); + PlaceholdersResolver resolver = getResolver(); List propertySources = new ArrayList<>(); getPropertySourcesAsMap().forEach((sourceName, source) -> { if (source instanceof EnumerablePropertySource) { @@ -99,7 +100,7 @@ public class EnvironmentEndpoint { } private PropertySourceDescriptor describeSource(String sourceName, - EnumerablePropertySource source, PropertyResolver resolver, + EnumerablePropertySource source, PlaceholdersResolver resolver, Predicate namePredicate) { Map properties = new LinkedHashMap<>(); Stream.of(source.getPropertyNames()).filter(namePredicate).forEach( @@ -108,19 +109,17 @@ public class EnvironmentEndpoint { } private PropertyValueDescriptor describeValueOf(String name, - EnumerablePropertySource source, PropertyResolver resolver) { - Object resolved = resolver.getProperty(name, Object.class); + EnumerablePropertySource source, PlaceholdersResolver resolver) { + Object resolved = resolver.resolvePlaceholders(source.getProperty(name)); @SuppressWarnings("unchecked") String origin = (source instanceof OriginLookup) ? ((OriginLookup) source).getOrigin(name).toString() : null; return new PropertyValueDescriptor(sanitize(name, resolved), origin); } - private PropertyResolver getResolver() { - PlaceholderSanitizingPropertyResolver resolver = new PlaceholderSanitizingPropertyResolver( + private PlaceholdersResolver getResolver() { + return new PropertySourcesPlaceholdersSanitizingResolver( getPropertySources(), this.sanitizer); - resolver.setIgnoreUnresolvableNestedPlaceholders(true); - return resolver; } private Map> getPropertySourcesAsMap() { @@ -160,29 +159,28 @@ public class EnvironmentEndpoint { } /** - * {@link PropertySourcesPropertyResolver} that sanitizes sensitive placeholders if - * present. + * {@link PropertySourcesPlaceholdersResolver} that sanitizes sensitive placeholders + * if present. */ - private class PlaceholderSanitizingPropertyResolver - extends PropertySourcesPropertyResolver { + private static class PropertySourcesPlaceholdersSanitizingResolver + extends PropertySourcesPlaceholdersResolver { private final Sanitizer sanitizer; - /** - * Create a new resolver against the given property sources. - * @param propertySources the set of {@link PropertySource} objects to use - * @param sanitizer the sanitizer used to sanitize sensitive values - */ - PlaceholderSanitizingPropertyResolver(PropertySources propertySources, - Sanitizer sanitizer) { - super(propertySources); + public PropertySourcesPlaceholdersSanitizingResolver( + Iterable> sources, Sanitizer sanitizer) { + super(sources, new PropertyPlaceholderHelper( + SystemPropertyUtils.PLACEHOLDER_PREFIX, + SystemPropertyUtils.PLACEHOLDER_SUFFIX, + SystemPropertyUtils.VALUE_SEPARATOR, true)); this.sanitizer = sanitizer; } @Override - protected String getPropertyAsRawString(String key) { - String value = super.getPropertyAsRawString(key); - return (String) this.sanitizer.sanitize(key, value); + protected String resolvePlaceholder(String placeholder) { + String value = super.resolvePlaceholder(placeholder); + return (value != null ? + (String) this.sanitizer.sanitize(placeholder, value) : null); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java index 50a496e7b57..8a3d1652073 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java @@ -76,6 +76,8 @@ public class EnvironmentEndpointTests { .environment(null); assertThat(getSource("composite:one", env).getProperties().get("foo").getValue()) .isEqualTo("bar"); + assertThat(getSource("composite:two", env).getProperties().get("foo").getValue()) + .isEqualTo("spam"); } @Test diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolver.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolver.java index 21e1b26714a..3dde32943a0 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolver.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolver.java @@ -63,7 +63,7 @@ public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver return value; } - private String resolvePlaceholder(String placeholder) { + protected String resolvePlaceholder(String placeholder) { if (this.sources != null) { for (PropertySource source : this.sources) { Object value = source.getProperty(placeholder);