From fa4de13519cd92a83d54d80516ae2b6702ab2b76 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 9 May 2017 20:53:47 -0700 Subject: [PATCH] Rework ConfigurationPropertySources Rework the ConfigurationPropertySources and related adapter classes to help with performance. The ConfigurationPropertySources class now only monitors for updates when `.attach` is used. The `.get` methods now return the adapted version, but no longer checks to see if sources have been added or removed on each call. This commit also fixes a few caching issues and makes both the `PropertyMapper` implementations true static singletons. See gh-9000 --- .../info/InfoPropertiesInfoContributor.java | 5 +- .../EndpointAutoConfigurationTests.java | 6 +- .../test/context/SpringBootContextLoader.java | 3 +- .../config/ConfigFileApplicationListener.java | 4 +- ...urationPropertiesBindingPostProcessor.java | 10 +- .../boot/context/properties/bind/Binder.java | 8 +- .../PropertySourcesPlaceholdersResolver.java | 6 +- .../source/ConfigurationPropertySources.java | 230 ++++++------------ ...gurationPropertySourcesPropertySource.java | 16 +- .../source/DefaultPropertyMapper.java | 61 +++-- .../MapConfigurationPropertySource.java | 5 +- .../properties/source/PropertyMapper.java | 6 +- .../properties/source/PropertyMapping.java | 2 +- ...=> SpringConfigurationPropertySource.java} | 80 +++++- .../SpringConfigurationPropertySources.java | 160 ++++++++++++ ...gIterableConfigurationPropertySource.java} | 23 +- .../SystemEnvironmentPropertyMapper.java | 7 +- .../boot/SpringApplicationTests.java | 4 +- .../LoggingApplicationListenerTests.java | 2 +- .../ConfigurationPropertySourcesTests.java | 190 +++------------ .../source/DefaultPropertyMapperTests.java | 4 +- ...ringConfigurationPropertySourceTests.java} | 71 +++++- ...ringConfigurationPropertySourcesTests.java | 135 ++++++++++ ...ableConfigurationPropertySourceTests.java} | 25 +- .../SystemEnvironmentPropertyMapperTests.java | 12 +- 25 files changed, 639 insertions(+), 436 deletions(-) rename spring-boot/src/main/java/org/springframework/boot/context/properties/source/{PropertySourceConfigurationPropertySource.java => SpringConfigurationPropertySource.java} (64%) create mode 100644 spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java rename spring-boot/src/main/java/org/springframework/boot/context/properties/source/{PropertySourceIterableConfigurationPropertySource.java => SpringIterableConfigurationPropertySource.java} (90%) rename spring-boot/src/test/java/org/springframework/boot/context/properties/source/{PropertySourceConfigurationPropertySourceTests.java => SpringConfigurationPropertySourceTests.java} (68%) create mode 100644 spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java rename spring-boot/src/test/java/org/springframework/boot/context/properties/source/{PropertySourceIterableConfigurationPropertySourceTests.java => SpringIterableConfigurationPropertySourceTests.java} (85%) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoPropertiesInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoPropertiesInfoContributor.java index 383c7472b96..94e81ab7ee4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoPropertiesInfoContributor.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoPropertiesInfoContributor.java @@ -25,7 +25,6 @@ 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.boot.info.InfoProperties; -import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.util.StringUtils; @@ -93,9 +92,7 @@ public abstract class InfoPropertiesInfoContributor * @return the raw content */ protected Map extractContent(PropertySource propertySource) { - MutablePropertySources sources = new MutablePropertySources(); - sources.addFirst(propertySource); - return new Binder(ConfigurationPropertySources.get(sources)) + return new Binder(ConfigurationPropertySources.from(propertySource)) .bind("", STRING_OBJECT_MAP).orElseGet(LinkedHashMap::new); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index e85f8a9b961..1a3ec8d2092 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import javax.sql.DataSource; @@ -320,9 +321,8 @@ public class EndpointAutoConfigurationTests { if (!location.exists()) { return; } - MapConfigurationPropertySource source = new MapConfigurationPropertySource( - PropertiesLoaderUtils.loadProperties(location)); - new Binder(source).bind("info", + Properties properties = PropertiesLoaderUtils.loadProperties(location); + new Binder(new MapConfigurationPropertySource(properties)).bind("info", Bindable.of(STRING_OBJECT_MAP).withExistingValue(this.content)); } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java index c984c2a9a6f..7f0f89d6644 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java @@ -28,6 +28,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.boot.test.mock.web.SpringBootMockServletContext; import org.springframework.boot.test.util.EnvironmentTestUtils; @@ -173,7 +174,7 @@ public class SpringBootContextLoader extends AbstractContextLoader { return binder.bind("server.port", Bindable.of(String.class)).isBound(); } - private MapConfigurationPropertySource convertToConfigurationPropertySource( + private ConfigurationPropertySource convertToConfigurationPropertySource( List properties) { String[] array = properties.toArray(new String[properties.size()]); return new MapConfigurationPropertySource( diff --git a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 3b065e384b7..b00f2d5cdca 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -480,9 +480,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, } private void handleProfileProperties(PropertySource propertySource) { - MutablePropertySources propertySources = new MutablePropertySources(); - propertySources.addFirst(propertySource); - Binder binder = new Binder(ConfigurationPropertySources.get(propertySources), + Binder binder = new Binder(ConfigurationPropertySources.from(propertySource), new PropertySourcesPlaceholdersResolver(this.environment)); Set active = getProfiles(binder, "spring.profiles.active"); Set include = getProfiles(binder, "spring.profiles.include"); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java index 2c3db47a9d2..3993358c834 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java @@ -40,6 +40,7 @@ import org.springframework.boot.context.properties.bind.PropertySourcesPlacehold import org.springframework.boot.context.properties.bind.handler.IgnoreErrorsBindHandler; 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.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.validation.MessageInterpolatorFactory; import org.springframework.context.ApplicationContext; @@ -59,6 +60,7 @@ 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.PropertySource; import org.springframework.core.env.PropertySources; import org.springframework.core.env.StandardEnvironment; import org.springframework.util.Assert; @@ -95,7 +97,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData(); - private PropertySources propertySources; + private Iterable> propertySources; private Validator validator; @@ -117,7 +119,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc private int order = Ordered.HIGHEST_PRECEDENCE + 1; - private ConfigurationPropertySources configurationSources; + private Iterable configurationSources; private Binder binder; @@ -164,7 +166,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc * Set the property sources to bind. * @param propertySources the property sources */ - public void setPropertySources(PropertySources propertySources) { + public void setPropertySources(Iterable> propertySources) { this.propertySources = propertySources; } @@ -221,7 +223,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc ConversionService.class); } this.configurationSources = ConfigurationPropertySources - .get(this.propertySources); + .from(this.propertySources); } @Override diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java index d5ad6b28b47..4bd44e660c4 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java @@ -37,7 +37,6 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyN import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.core.convert.ConversionService; -import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.Assert; @@ -331,13 +330,12 @@ public class Binder { /** * Create a new {@link Binder} instance from the specified environment. - * @param environment the environment (must be a {@link ConfigurableEnvironment}) + * @param environment the environment source (must have attached + * {@link ConfigurationPropertySources}) * @return a {@link Binder} instance */ public static Binder get(Environment environment) { - Assert.isInstanceOf(ConfigurableEnvironment.class, environment); - return new Binder( - ConfigurationPropertySources.get((ConfigurableEnvironment) environment), + return new Binder(ConfigurationPropertySources.get(environment), new PropertySourcesPlaceholdersResolver(environment)); } 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 c18f8210a48..21e1b26714a 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 @@ -33,7 +33,7 @@ import org.springframework.util.SystemPropertyUtils; */ public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver { - private final PropertySources sources; + private final Iterable> sources; private final PropertyPlaceholderHelper helper; @@ -41,11 +41,11 @@ public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver this(getSources(environment), null); } - public PropertySourcesPlaceholdersResolver(PropertySources sources) { + public PropertySourcesPlaceholdersResolver(Iterable> sources) { this(sources, null); } - public PropertySourcesPlaceholdersResolver(PropertySources sources, + public PropertySourcesPlaceholdersResolver(Iterable> sources, PropertyPlaceholderHelper helper) { this.sources = sources; this.helper = (helper != null ? helper diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java index 0bcddbb5acb..798f8531036 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java @@ -16,197 +16,125 @@ package org.springframework.boot.context.properties.source; -import java.util.Iterator; -import java.util.Map; -import java.util.Optional; -import java.util.WeakHashMap; -import java.util.function.Function; +import java.util.Collections; +import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import org.springframework.boot.env.RandomValuePropertySource; 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.PropertySource; import org.springframework.core.env.PropertySource.StubPropertySource; -import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySourcesPropertyResolver; -import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.util.Assert; /** - * A managed set of {@link ConfigurationPropertySource} instances, usually adapted from - * Spring's {@link PropertySources}. + * Provides access to {@link ConfigurationPropertySource ConfigurationPropertySources}. * * @author Phillip Webb - * @author Madhura Bhave * @since 2.0.0 - * @see #attach(MutablePropertySources) - * @see #get(PropertySources) */ -public class ConfigurationPropertySources - implements Iterable { - - private static final ConfigurationPropertyName RANDOM = ConfigurationPropertyName - .of("random"); +public final class ConfigurationPropertySources { /** * The name of the {@link PropertySource} {@link #adapt adapter}. */ - public static final String PROPERTY_SOURCE_NAME = "configurationProperties"; - - private final PropertySources propertySources; + private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties"; - private final Map, ConfigurationPropertySource> adapters = new WeakHashMap<>(); + private ConfigurationPropertySources() { + } /** - * Create a new {@link ConfigurationPropertySources} instance. - * @param propertySources the property sources to expose + * Attach a {@link ConfigurationPropertySource} support to the specified + * {@link Environment}. Adapts each {@link PropertySource} managed by the environment + * to a {@link ConfigurationPropertySource} and allows classic + * {@link PropertySourcesPropertyResolver} calls to resolve using + * {@link ConfigurationPropertyName configuration property names}. + *

+ * The attached resolver will dynamically track any additions or removals from the + * underlying {@link Environment} property sources. + * @param environment the source environment (must be an instance of + * {@link ConfigurableEnvironment}) + * @see #get(Environment) */ - ConfigurationPropertySources(PropertySources propertySources) { - Assert.notNull(propertySources, "PropertySources must not be null"); - this.propertySources = propertySources; - } - - @Override - public Iterator iterator() { - return streamPropertySources(this.propertySources) - .filter(s -> !(s instanceof ConfigurationPropertySourcesPropertySource)) - .map(this::adapt).iterator(); - } - - private Stream> streamPropertySources(PropertySources sources) { - return StreamSupport.stream(sources.spliterator(), false).flatMap(this::flatten) - .filter(this::notStubSource); - } - - private Stream> flatten(PropertySource source) { - if (source.getSource() instanceof ConfigurableEnvironment) { - return streamPropertySources( - ((ConfigurableEnvironment) source.getSource()).getPropertySources()); + public static void attach(Environment environment) { + Assert.isInstanceOf(ConfigurableEnvironment.class, environment); + MutablePropertySources sources = ((ConfigurableEnvironment) environment) + .getPropertySources(); + if (!sources.contains(ATTACHED_PROPERTY_SOURCE_NAME)) { + sources.addFirst(new ConfigurationPropertySourcesPropertySource( + ATTACHED_PROPERTY_SOURCE_NAME, + new SpringConfigurationPropertySources(sources))); } - return Stream.of(source); - } - - private boolean notStubSource(PropertySource source) { - return !(source instanceof StubPropertySource); - } - - private ConfigurationPropertySource adapt(PropertySource source) { - return this.adapters.computeIfAbsent(source, this::createAdapter); } - private ConfigurationPropertySource createAdapter(PropertySource source) { - PropertyMapper mapper = getPropertyMapper(source); - if (isFullEnumerable(source)) { - return new PropertySourceIterableConfigurationPropertySource( - (EnumerablePropertySource) source, mapper); - } - return new PropertySourceConfigurationPropertySource(source, mapper, - getContainsDescendantOfMethod(source)); - } - - private PropertyMapper getPropertyMapper(PropertySource source) { - if (source instanceof SystemEnvironmentPropertySource) { - return SystemEnvironmentPropertyMapper.INSTANCE; - } - return DefaultPropertyMapper.INSTANCE; - } - - private boolean isFullEnumerable(PropertySource source) { - PropertySource rootSource = getRootSource(source); - if (rootSource.getSource() instanceof Map) { - // Check we're not security restricted - try { - ((Map) rootSource.getSource()).size(); - } - catch (UnsupportedOperationException ex) { - return false; - } - } - return (source instanceof EnumerablePropertySource); - } - - private PropertySource getRootSource(PropertySource source) { - while (source.getSource() != null - && source.getSource() instanceof PropertySource) { - source = (PropertySource) source.getSource(); - } - return source; - } - - private Function> getContainsDescendantOfMethod( - PropertySource source) { - if (source instanceof RandomValuePropertySource) { - return (name) -> Optional - .of(name.isAncestorOf(RANDOM) || name.equals(RANDOM)); + /** + * Return a set of {@link ConfigurationPropertySource} instances that have previously + * been {@link #attach(Environment) attached} to the {@link Environment}. + * @param environment the source environment (must be an instance of + * {@link ConfigurableEnvironment}) + * @return an iterable set of configuration property sources + * @throws IllegalStateException if not configuration property sources have been + * attached + */ + public static Iterable get(Environment environment) { + Assert.isInstanceOf(ConfigurableEnvironment.class, environment); + MutablePropertySources sources = ((ConfigurableEnvironment) environment) + .getPropertySources(); + ConfigurationPropertySourcesPropertySource attached = (ConfigurationPropertySourcesPropertySource) sources + .get(ATTACHED_PROPERTY_SOURCE_NAME); + if (attached == null) { + return from(sources); } - return null; + return attached.getSource(); } /** - * Attach a {@link ConfigurationPropertySources} instance to the specified - * {@link ConfigurableEnvironment} so that classic - * {@link PropertySourcesPropertyResolver} calls will resolve using - * {@link ConfigurationPropertyName configuration property names}. - * @param environment the source environment - * @return the instance attached + * Return {@link Iterable} containing a single new {@link ConfigurationPropertySource} + * adapted from the given Spring {@link PropertySource}. + * @param source the Spring property source to adapt + * @return an {@link Iterable} containing a single newly adapted + * {@link SpringConfigurationPropertySource} */ - public static ConfigurationPropertySources attach( - ConfigurableEnvironment environment) { - return attach(environment.getPropertySources()); + public static Iterable from(PropertySource source) { + return Collections.singleton(SpringConfigurationPropertySource.from(source)); } /** - * Attach a {@link ConfigurationPropertySources} instance to the specified - * {@link PropertySources} so that classic {@link PropertySourcesPropertyResolver} - * calls will resolve using using {@link ConfigurationPropertyName configuration - * property names}. - * @param propertySources the source property sources - * @return the instance attached + * Return {@link Iterable} containing new {@link ConfigurationPropertySource} + * instances adapted from the given Spring {@link PropertySource PropertySources}. + *

+ * This method will flatten any nested property sources and will filter all + * {@link StubPropertySource stub property sources}. + * @param sources the Spring property sources to adapt + * @return an {@link Iterable} containing a single newly adapted + * {@link SpringConfigurationPropertySource} instances */ - public static ConfigurationPropertySources attach( - MutablePropertySources propertySources) { - ConfigurationPropertySources adapted = new ConfigurationPropertySources( - propertySources); - propertySources.addFirst(new ConfigurationPropertySourcesPropertySource( - PROPERTY_SOURCE_NAME, adapted)); - return adapted; + public static Iterable from( + Iterable> sources) { + return streamPropertySources(sources).map(SpringConfigurationPropertySource::from) + .collect(Collectors.toList()); } - /** - * Get a {@link ConfigurationPropertySources} instance for the specified - * {@link PropertySources} (either previously {@link #attach(MutablePropertySources) - * attached} or a new instance. - * @param propertySources the source property sources - * @return a {@link ConfigurationPropertySources} instance - */ - public static ConfigurationPropertySources get(PropertySources propertySources) { - if (propertySources == null) { - return null; - } - PropertySource source = propertySources.get(PROPERTY_SOURCE_NAME); - if (source != null) { - return (ConfigurationPropertySources) source.getSource(); - } - return new ConfigurationPropertySources(propertySources); + private static Stream> streamPropertySources( + Iterable> sources) { + return StreamSupport.stream(sources.spliterator(), false) + .flatMap(ConfigurationPropertySources::flatten) + .filter(ConfigurationPropertySources::isIncluded); } - /** - * Get a {@link ConfigurationPropertySources} instance for the {@link PropertySources} - * from the specified {@link ConfigurableEnvironment}, (either previously - * {@link #attach(MutablePropertySources) attached} or a new instance. - * @param environment the configurable environment - * @return a {@link ConfigurationPropertySources} instance - */ - public static ConfigurationPropertySources get(ConfigurableEnvironment environment) { - MutablePropertySources propertySources = environment.getPropertySources(); - PropertySource source = propertySources.get(PROPERTY_SOURCE_NAME); - if (source != null) { - return (ConfigurationPropertySources) source.getSource(); + private static Stream> flatten(PropertySource source) { + if (source.getSource() instanceof ConfigurableEnvironment) { + return streamPropertySources( + ((ConfigurableEnvironment) source.getSource()).getPropertySources()); } - return new ConfigurationPropertySources(propertySources); + return Stream.of(source); + } + + private static boolean isIncluded(PropertySource source) { + return !(source instanceof StubPropertySource) + && !(source instanceof ConfigurationPropertySourcesPropertySource); } } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java index dfe3f8bad4c..365fd488729 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java @@ -16,10 +16,6 @@ package org.springframework.boot.context.properties.source; -import java.util.Objects; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginLookup; import org.springframework.core.env.Environment; @@ -70,10 +66,14 @@ class ConfigurationPropertySourcesPropertySource if (name == null) { return null; } - Stream sources = StreamSupport - .stream(getSource().spliterator(), false); - return sources.map(source -> source.getConfigurationProperty(name)) - .filter(Objects::nonNull).findFirst().orElse(null); + for (ConfigurationPropertySource configurationPropertySource : getSource()) { + ConfigurationProperty configurationProperty = configurationPropertySource + .getConfigurationProperty(name); + if (configurationProperty != null) { + return configurationProperty; + } + } + return null; } } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/DefaultPropertyMapper.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/DefaultPropertyMapper.java index 5ef4443d129..5259c5e4aa9 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/DefaultPropertyMapper.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/DefaultPropertyMapper.java @@ -17,11 +17,10 @@ package org.springframework.boot.context.properties.source; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.springframework.core.env.PropertySource; +import org.springframework.util.ObjectUtils; /** * Default {@link PropertyMapper} implementation. Names are mapped by removing invalid @@ -31,36 +30,48 @@ import org.springframework.core.env.PropertySource; * @author Phillip Webb * @author Madhura Bhave * @see PropertyMapper - * @see PropertySourceConfigurationPropertySource + * @see SpringConfigurationPropertySource */ -class DefaultPropertyMapper implements PropertyMapper { +final class DefaultPropertyMapper implements PropertyMapper { public static final PropertyMapper INSTANCE = new DefaultPropertyMapper(); - private final Cache configurationPropertySourceCache = new Cache<>(); + private LastMapping lastMappedConfigurationPropertyName; - private final Cache propertySourceCache = new Cache<>(); + private LastMapping lastMappedPropertyName; private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder(); + private DefaultPropertyMapper() { + } + @Override public List map(PropertySource propertySource, ConfigurationPropertyName configurationPropertyName) { - List mapping = this.configurationPropertySourceCache - .get(configurationPropertyName); - if (mapping == null) { - String convertedName = configurationPropertyName.toString(); - mapping = Collections.singletonList( - new PropertyMapping(convertedName, configurationPropertyName)); - this.configurationPropertySourceCache.put(configurationPropertyName, mapping); + // Use a local copy in case another thread changes things + LastMapping last = this.lastMappedConfigurationPropertyName; + if (last != null && last.isFrom(configurationPropertyName)) { + return last.getMapping(); } + String convertedName = configurationPropertyName.toString(); + List mapping = Collections.singletonList( + new PropertyMapping(convertedName, configurationPropertyName)); + this.lastMappedConfigurationPropertyName = new LastMapping<>( + configurationPropertyName, mapping); return mapping; } @Override public List map(PropertySource propertySource, String propertySourceName) { - return this.propertySourceCache.computeIfAbsent(propertySourceName, this::tryMap); + // Use a local copy in case another thread changes things + LastMapping last = this.lastMappedPropertyName; + if (last != null && last.isFrom(propertySourceName)) { + return last.getMapping(); + } + List mapping = tryMap(propertySourceName); + this.lastMappedPropertyName = new LastMapping<>(propertySourceName, mapping); + return mapping; } private List tryMap(String propertySourceName) { @@ -75,23 +86,23 @@ class DefaultPropertyMapper implements PropertyMapper { } } - private static class Cache extends LinkedHashMap> { + private static class LastMapping { - private final int capacity; + private final T from; - Cache() { - this(1); - } + private final List mapping; - Cache(int capacity) { - super(capacity, (float) 0.75, true); - this.capacity = capacity; + LastMapping(T from, List mapping) { + this.from = from; + this.mapping = mapping; } - @Override - protected boolean removeEldestEntry(Map.Entry> eldest) { - return size() > this.capacity; + public boolean isFrom(T from) { + return ObjectUtils.nullSafeEquals(from, this.from); + } + public List getMapping() { + return this.mapping; } } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySource.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySource.java index cc7bb87e47c..1ac954c7371 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySource.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySource.java @@ -31,7 +31,6 @@ import org.springframework.util.Assert; * * @author Phillip Webb * @author Madhura Bhave - * @since 2.0.0 */ public class MapConfigurationPropertySource implements IterableConfigurationPropertySource { @@ -54,9 +53,9 @@ public class MapConfigurationPropertySource */ public MapConfigurationPropertySource(Map map) { this.source = new LinkedHashMap<>(); - this.delegate = new PropertySourceIterableConfigurationPropertySource( + this.delegate = new SpringIterableConfigurationPropertySource( new MapPropertySource("source", this.source), - new DefaultPropertyMapper()); + DefaultPropertyMapper.INSTANCE); putAll(map); } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapper.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapper.java index c1d5d8164e8..30ff036c6e2 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapper.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapper.java @@ -27,16 +27,16 @@ import org.springframework.core.env.PropertySource; *

* Mappings should be provided for both {@link ConfigurationPropertyName * ConfigurationPropertyName} types and {@code String} based names. This allows the - * {@link PropertySourceConfigurationPropertySource} to first attempt any direct mappings + * {@link SpringConfigurationPropertySource} to first attempt any direct mappings * (i.e. map the {@link ConfigurationPropertyName} directly to the {@link PropertySource} * name) before falling back to {@link EnumerablePropertySource enumerating} property * names, mapping them to a {@link ConfigurationPropertyName} and checking for * {@link PropertyMapping#isApplicable(ConfigurationPropertyName) applicability}. See - * {@link PropertySourceConfigurationPropertySource} for more details. + * {@link SpringConfigurationPropertySource} for more details. * * @author Phillip Webb * @author Madhura Bhave - * @see PropertySourceConfigurationPropertySource + * @see SpringConfigurationPropertySource */ interface PropertyMapper { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapping.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapping.java index be604392822..d6badbd6a8f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapping.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapping.java @@ -26,7 +26,7 @@ import org.springframework.core.env.PropertySource; * * @author Phillip Webb * @author Madhura Bhave - * @see PropertySourceConfigurationPropertySource + * @see SpringConfigurationPropertySource */ class PropertyMapping { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySource.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java similarity index 64% rename from spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySource.java rename to spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java index 92167ac1cd8..b3d37d7ea9d 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySource.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java @@ -18,14 +18,17 @@ package org.springframework.boot.context.properties.source; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import org.springframework.boot.env.RandomValuePropertySource; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.util.Assert; /** @@ -41,16 +44,19 @@ import org.springframework.util.Assert; * {@link ConfigurationPropertyName} to one or more {@code String} based names. This * allows fast property resolution for well formed property sources. *

- * If at all possible the {@link PropertySourceIterableConfigurationPropertySource} should - * be used in preference to this implementation since it supports "relaxed" style - * resolution. + * When possible the {@link SpringIterableConfigurationPropertySource} will be used in + * preference to this implementation since it supports full "relaxed" style resolution. * * @author Phillip Webb * @author Madhura Bhave + * @see #from(PropertySource) * @see PropertyMapper - * @see PropertySourceIterableConfigurationPropertySource + * @see SpringIterableConfigurationPropertySource */ -class PropertySourceConfigurationPropertySource implements ConfigurationPropertySource { +class SpringConfigurationPropertySource implements ConfigurationPropertySource { + + private static final ConfigurationPropertyName RANDOM = ConfigurationPropertyName + .of("random"); private final PropertySource propertySource; @@ -59,21 +65,21 @@ class PropertySourceConfigurationPropertySource implements ConfigurationProperty private final Function> containsDescendantOfMethod; /** - * Create a new {@link PropertySourceConfigurationPropertySource} implementation. + * Create a new {@link SpringConfigurationPropertySource} implementation. * @param propertySource the source property source * @param mapper the property mapper * @param containsDescendantOfMethod function used to implement * {@link #containsDescendantOf(ConfigurationPropertyName)} (may be {@code null}) */ - PropertySourceConfigurationPropertySource(PropertySource propertySource, + SpringConfigurationPropertySource(PropertySource propertySource, PropertyMapper mapper, Function> containsDescendantOfMethod) { Assert.notNull(propertySource, "PropertySource must not be null"); Assert.notNull(mapper, "Mapper must not be null"); this.propertySource = propertySource; this.mapper = new ExceptionSwallowingPropertyMapper(mapper); - this.containsDescendantOfMethod = (containsDescendantOfMethod != null ? containsDescendantOfMethod - : (n) -> Optional.empty()); + this.containsDescendantOfMethod = (containsDescendantOfMethod != null + ? containsDescendantOfMethod : (n) -> Optional.empty()); } @Override @@ -120,6 +126,62 @@ class PropertySourceConfigurationPropertySource implements ConfigurationProperty return this.propertySource.toString(); } + /** + * Create a new {@link SpringConfigurationPropertySource} for the specified + * {@link PropertySource}. + * @param source the source Spring {@link PropertySource} + * @return a {@link SpringConfigurationPropertySource} or + * {@link SpringIterableConfigurationPropertySource} instance + */ + public static SpringConfigurationPropertySource from(PropertySource source) { + Assert.notNull(source, "Source must not be null"); + PropertyMapper mapper = getPropertyMapper(source); + if (isFullEnumerable(source)) { + return new SpringIterableConfigurationPropertySource( + (EnumerablePropertySource) source, mapper); + } + return new SpringConfigurationPropertySource(source, mapper, + getContainsDescendantOfMethod(source)); + } + + private static PropertyMapper getPropertyMapper(PropertySource source) { + if (source instanceof SystemEnvironmentPropertySource) { + return SystemEnvironmentPropertyMapper.INSTANCE; + } + return DefaultPropertyMapper.INSTANCE; + } + + private static boolean isFullEnumerable(PropertySource source) { + PropertySource rootSource = getRootSource(source); + if (rootSource.getSource() instanceof Map) { + // Check we're not security restricted + try { + ((Map) rootSource.getSource()).size(); + } + catch (UnsupportedOperationException ex) { + return false; + } + } + return (source instanceof EnumerablePropertySource); + } + + private static PropertySource getRootSource(PropertySource source) { + while (source.getSource() != null + && source.getSource() instanceof PropertySource) { + source = (PropertySource) source.getSource(); + } + return source; + } + + private static Function> getContainsDescendantOfMethod( + PropertySource source) { + if (source instanceof RandomValuePropertySource) { + return (name) -> Optional + .of(name.isAncestorOf(RANDOM) || name.equals(RANDOM)); + } + return null; + } + /** * {@link PropertyMapper} that swallows exceptions when the mapping fails. */ diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java new file mode 100644 index 00000000000..7933996a47b --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java @@ -0,0 +1,160 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.context.properties.source; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.PropertySource.StubPropertySource; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * Adapter to convert Spring's {@link MutablePropertySources} to + * {@link ConfigurationPropertySource ConfigurationPropertySources}. + * + * @author Phillip Webb + */ +class SpringConfigurationPropertySources + implements Iterable { + + private final MutablePropertySources sources; + + private volatile PropertySourcesKey lastKey; + + private volatile List adaptedSources; + + SpringConfigurationPropertySources(MutablePropertySources sources) { + Assert.notNull(sources, "Sources must not be null"); + this.sources = sources; + } + + @Override + public Iterator iterator() { + checkForChanges(); + return this.adaptedSources.iterator(); + } + + private void checkForChanges() { + PropertySourcesKey lastKey = this.lastKey; + PropertySourcesKey currentKey = new PropertySourcesKey(this.sources); + if (!currentKey.equals(lastKey)) { + onChange(this.sources); + this.lastKey = currentKey; + } + } + + private void onChange(MutablePropertySources sources) { + this.adaptedSources = streamPropertySources(sources) + .map(SpringConfigurationPropertySource::from) + .collect(Collectors.toList()); + } + + private Stream> streamPropertySources( + Iterable> sources) { + return StreamSupport.stream(sources.spliterator(), false).flatMap(this::flatten) + .filter(this::isIncluded); + } + + private Stream> flatten(PropertySource source) { + if (source.getSource() instanceof ConfigurableEnvironment) { + return streamPropertySources( + ((ConfigurableEnvironment) source.getSource()).getPropertySources()); + } + return Stream.of(source); + } + + private boolean isIncluded(PropertySource source) { + return !(source instanceof StubPropertySource) + && !(source instanceof ConfigurationPropertySourcesPropertySource); + } + + private static class PropertySourcesKey { + + private final List keys = new ArrayList<>(); + + PropertySourcesKey(MutablePropertySources sources) { + sources.forEach(this::addKey); + } + + private void addKey(PropertySource source) { + this.keys.add(new PropertySourceKey(source)); + } + + @Override + public int hashCode() { + return this.keys.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return this.keys.equals(((PropertySourcesKey) obj).keys); + } + + } + + private static class PropertySourceKey { + + private final String name; + + private final Class type; + + PropertySourceKey(PropertySource source) { + this.name = source.getName(); + this.type = source.getClass(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ObjectUtils.nullSafeHashCode(this.name); + result = prime * result + ObjectUtils.nullSafeHashCode(this.type); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + PropertySourceKey other = (PropertySourceKey) obj; + boolean result = true; + result = result && ObjectUtils.nullSafeEquals(this.name, other.name); + result = result && ObjectUtils.nullSafeEquals(this.type, other.type); + return result; + } + + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySource.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java similarity index 90% rename from spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySource.java rename to spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java index f017b3457d2..0a5c2303e11 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySource.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java @@ -31,21 +31,24 @@ import org.springframework.util.ObjectUtils; /** * {@link ConfigurationPropertySource} backed by a {@link EnumerablePropertySource}. - * Extends {@link PropertySourceConfigurationPropertySource} with full "relaxed" mapping - * support. In order to use this adapter the underlying {@link PropertySource} must be - * fully enumerable. A security restricted {@link SystemEnvironmentPropertySource} cannot - * be adapted. + * Extends {@link SpringConfigurationPropertySource} with full "relaxed" mapping support. + * In order to use this adapter the underlying {@link PropertySource} must be fully + * enumerable. A security restricted {@link SystemEnvironmentPropertySource} cannot be + * adapted. * * @author Phillip Webb * @author Madhura Bhave * @see PropertyMapper */ -class PropertySourceIterableConfigurationPropertySource - extends PropertySourceConfigurationPropertySource +class SpringIterableConfigurationPropertySource extends SpringConfigurationPropertySource implements IterableConfigurationPropertySource { - PropertySourceIterableConfigurationPropertySource( - EnumerablePropertySource propertySource, PropertyMapper mapper) { + private volatile Object cacheKey; + + private volatile Cache cache; + + SpringIterableConfigurationPropertySource(EnumerablePropertySource propertySource, + PropertyMapper mapper) { super(propertySource, mapper, null); assertEnumerablePropertySource(propertySource); } @@ -63,10 +66,6 @@ class PropertySourceIterableConfigurationPropertySource } } - private volatile Object cacheKey; - - private volatile Cache cache; - @Override public ConfigurationProperty getConfigurationProperty( ConfigurationPropertyName name) { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapper.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapper.java index 5389e2ff9f0..c8f4dcd5613 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapper.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapper.java @@ -41,15 +41,18 @@ import org.springframework.util.StringUtils; * @author Phillip Webb * @author Madhura Bhave * @see PropertyMapper - * @see PropertySourceConfigurationPropertySource + * @see SpringConfigurationPropertySource */ -class SystemEnvironmentPropertyMapper implements PropertyMapper { +final class SystemEnvironmentPropertyMapper implements PropertyMapper { public static final PropertyMapper INSTANCE = new SystemEnvironmentPropertyMapper(); private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder( this::createElement); + private SystemEnvironmentPropertyMapper() { + } + @Override public List map(PropertySource propertySource, String propertySourceName) { diff --git a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 575358c705b..2e720ae3a24 100644 --- a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -48,7 +48,6 @@ import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEven import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationStartingEvent; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; @@ -868,8 +867,7 @@ public class SpringApplicationTests { assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bar"); Iterator> iterator = this.context.getEnvironment() .getPropertySources().iterator(); - assertThat(iterator.next().getName()) - .isEqualTo(ConfigurationPropertySources.PROPERTY_SOURCE_NAME); + assertThat(iterator.next().getName()).isEqualTo("configurationProperties"); assertThat(iterator.next().getName()).isEqualTo( TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME); } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java index 6e413b084ec..97865a7e989 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java @@ -105,7 +105,7 @@ public class LoggingApplicationListenerTests { new File("target/foo.log").delete(); new File(tmpDir() + "/spring.log").delete(); ConfigurableEnvironment environment = this.context.getEnvironment(); - ConfigurationPropertySources.attach(environment.getPropertySources()); + ConfigurationPropertySources.attach(environment); } @After diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java index 8e40299a2f9..8fede0d629a 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java @@ -17,7 +17,6 @@ package org.springframework.boot.context.properties.source; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -25,7 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.boot.env.RandomValuePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; @@ -41,180 +40,69 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link ConfigurationPropertySources}. * * @author Phillip Webb - * @author Madhura Bhave */ public class ConfigurationPropertySourcesTests { @Rule public ExpectedException thrown = ExpectedException.none(); - @Test - public void createWhenPropertySourcesIsNullShouldThrowException() throws Exception { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("PropertySources must not be null"); - new ConfigurationPropertySources(null); - } - - @Test - public void iteratorShouldAdaptPropertySource() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); - sources.addFirst(new MapPropertySource("test", - Collections.singletonMap("a", "b"))); - Iterator iterator = new ConfigurationPropertySources( - sources).iterator(); - assertThat(iterator.next() - .getConfigurationProperty(ConfigurationPropertyName.of("a")).getValue()) - .isEqualTo("b"); - assertThat(iterator.hasNext()).isFalse(); - } - - @Test - public void iteratorShouldAdaptSystemEnvironmentPropertySource() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); - sources.addLast(new SystemEnvironmentPropertySource("system", - Collections.singletonMap("SERVER_PORT", "1234"))); - Iterator iterator = new ConfigurationPropertySources( - sources).iterator(); - assertThat( - iterator.next() - .getConfigurationProperty( - ConfigurationPropertyName.of("server.port")) - .getValue()).isEqualTo("1234"); - assertThat(iterator.hasNext()).isFalse(); - } - - @Test - public void iteratorShouldAdaptMultiplePropertySources() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); - sources.addLast(new SystemEnvironmentPropertySource("system", - Collections.singletonMap("SERVER_PORT", "1234"))); - sources.addLast(new MapPropertySource("test1", - Collections.singletonMap("server.po-rt", "4567"))); - sources.addLast(new MapPropertySource("test2", - Collections.singletonMap("a", "b"))); - Iterator iterator = new ConfigurationPropertySources( - sources).iterator(); - assertThat( - iterator.next() - .getConfigurationProperty( - ConfigurationPropertyName.of("server.port")) - .getValue()).isEqualTo("1234"); - assertThat( - iterator.next() - .getConfigurationProperty( - ConfigurationPropertyName.of("server.port")) - .getValue()).isEqualTo("4567"); - assertThat(iterator.next() - .getConfigurationProperty(ConfigurationPropertyName.of("a")).getValue()) - .isEqualTo("b"); - assertThat(iterator.hasNext()).isFalse(); - } - @Test public void attachShouldAddAdapterAtBeginning() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); + ConfigurableEnvironment environment = new StandardEnvironment(); + MutablePropertySources sources = environment.getPropertySources(); sources.addLast(new SystemEnvironmentPropertySource("system", Collections.singletonMap("SERVER_PORT", "1234"))); sources.addLast(new MapPropertySource("config", Collections.singletonMap("server.port", "4568"))); - assertThat(sources.size()).isEqualTo(2); - ConfigurationPropertySources.attach(sources); + int size = sources.size(); + ConfigurationPropertySources.attach(environment); + assertThat(sources.size()).isEqualTo(size + 1); PropertyResolver resolver = new PropertySourcesPropertyResolver(sources); assertThat(resolver.getProperty("server.port")).isEqualTo("1234"); - assertThat(sources.size()).isEqualTo(3); } @Test - public void getWhenAttachedShouldReturnAttached() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); - sources.addFirst(new MapPropertySource("test", - Collections.singletonMap("a", "b"))); - ConfigurationPropertySources attached = ConfigurationPropertySources - .attach(sources); - assertThat(ConfigurationPropertySources.get(sources)).isSameAs(attached); + public void getWhenNotAttachedShouldReturnAdapted() throws Exception { + ConfigurableEnvironment environment = new StandardEnvironment(); + assertThat(ConfigurationPropertySources.get(environment)).isNotEmpty(); } @Test - public void getWhenNotAttachedShouldReturnNew() throws Exception { - MutablePropertySources sources = new MutablePropertySources(); + public void getWhenAttachedShouldReturnAttached() throws Exception { + ConfigurableEnvironment environment = new StandardEnvironment(); + MutablePropertySources sources = environment.getPropertySources(); sources.addFirst(new MapPropertySource("test", Collections.singletonMap("a", "b"))); - assertThat(ConfigurationPropertySources.get(sources)).isNotNull(); - assertThat(sources.size()).isEqualTo(1); - } - - @Test - public void getWhenNonEnumerableShouldNotBeIterable() throws Exception { - StandardEnvironment environment = new StandardEnvironment(); - Map source = new LinkedHashMap() { - - @Override - public int size() { - throw new UnsupportedOperationException("Same as security restricted"); - } - - }; - PropertySource propertySource = new MapPropertySource("test", source); - environment.getPropertySources().addFirst(propertySource); - ConfigurationPropertySources sources = ConfigurationPropertySources - .get(environment); - ConfigurationPropertySource configurationPropertySource = sources.iterator() - .next(); - assertThat(configurationPropertySource) - .isNotInstanceOf(IterableConfigurationPropertySource.class); - } - - @Test - public void getWhenEnumerableButRestrictedShouldNotBeIterable() throws Exception { - StandardEnvironment environment = new StandardEnvironment(); - PropertySource propertySource = new PropertySource("test", - new Object()) { - - @Override - public Object getProperty(String name) { - return null; - } - - }; - environment.getPropertySources().addFirst(propertySource); - ConfigurationPropertySources sources = ConfigurationPropertySources - .get(environment); - ConfigurationPropertySource configurationPropertySource = sources.iterator() - .next(); - assertThat(configurationPropertySource) - .isNotInstanceOf(IterableConfigurationPropertySource.class); + int expectedSize = sources.size(); + ConfigurationPropertySources.attach(environment); + assertThat(ConfigurationPropertySources.get(environment)).hasSize(expectedSize); } @Test - public void getWhenEnumerableShouldBeIterable() throws Exception { - StandardEnvironment environment = new StandardEnvironment(); + public void environmentProperyExpansionShouldWorkWhenAttached() throws Exception { + ConfigurableEnvironment environment = new StandardEnvironment(); Map source = new LinkedHashMap<>(); source.put("fooBar", "Spring ${barBaz} ${bar-baz}"); source.put("barBaz", "Boot"); PropertySource propertySource = new MapPropertySource("test", source); environment.getPropertySources().addFirst(propertySource); - ConfigurationPropertySources sources = ConfigurationPropertySources - .get(environment); - ConfigurationPropertySource configurationPropertySource = sources.iterator() - .next(); - assertThat(configurationPropertySource) - .isInstanceOf(IterableConfigurationPropertySource.class); + ConfigurationPropertySources.attach(environment); + assertThat(environment.getProperty("foo-bar")).isEqualTo("Spring Boot Boot"); } @Test - public void environmentPropertyExpansionShouldWorkWhenAttached() throws Exception { - StandardEnvironment environment = new StandardEnvironment(); - Map source = new LinkedHashMap<>(); - source.put("fooBar", "Spring ${barBaz} ${bar-baz}"); - source.put("barBaz", "Boot"); - PropertySource propertySource = new MapPropertySource("test", source); - environment.getPropertySources().addFirst(propertySource); - ConfigurationPropertySources.attach(environment); - assertThat(environment.getProperty("foo-bar")).isEqualTo("Spring Boot Boot"); + public void fromPropertySourceShouldReturnSpringConfigurationPropertySource() + throws Exception { + PropertySource source = new MapPropertySource("foo", + Collections.singletonMap("foo", "bar")); + ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySources + .from(source).iterator().next(); + assertThat(configurationPropertySource) + .isInstanceOf(SpringConfigurationPropertySource.class); } @Test - public void environmentSourceShouldBeFlattened() throws Exception { + public void fromPropertySourcseShouldFlattenPropertySources() throws Exception { StandardEnvironment environment = new StandardEnvironment(); environment.getPropertySources().addFirst(new MapPropertySource("foo", Collections.singletonMap("foo", "bar"))); @@ -231,27 +119,9 @@ public class ConfigurationPropertySourcesTests { }); sources.addLast(new MapPropertySource("baz", Collections.singletonMap("baz", "barf"))); - ConfigurationPropertySources configurationSources = ConfigurationPropertySources - .get(sources); + Iterable configurationSources = ConfigurationPropertySources + .from(sources); assertThat(configurationSources.iterator()).hasSize(5); } - @Test - public void containsDescendantOfForRandomSourceShouldDetectNamesStartingRandom() - throws Exception { - StandardEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addFirst(new RandomValuePropertySource()); - ConfigurationPropertySource source = ConfigurationPropertySources.get(environment) - .iterator().next(); - assertThat(source.containsDescendantOf(ConfigurationPropertyName.of(""))) - .contains(true); - assertThat(source.containsDescendantOf(ConfigurationPropertyName.of("random"))) - .contains(true); - assertThat(source.containsDescendantOf(ConfigurationPropertyName.of("other"))) - .contains(false); - assertThat( - source.containsDescendantOf(ConfigurationPropertyName.of("random.foo"))) - .contains(false); - } - } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/DefaultPropertyMapperTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/DefaultPropertyMapperTests.java index c03b0968b37..8154ee8e14a 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/DefaultPropertyMapperTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/DefaultPropertyMapperTests.java @@ -28,11 +28,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class DefaultPropertyMapperTests extends AbstractPropertyMapperTests { - private DefaultPropertyMapper mapper = new DefaultPropertyMapper(); - @Override protected PropertyMapper getMapper() { - return this.mapper; + return DefaultPropertyMapper.INSTANCE; } @Test diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySourceTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java similarity index 68% rename from spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySourceTests.java rename to spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java index 9823354a7c1..e0f02f29735 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceConfigurationPropertySourceTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java @@ -32,12 +32,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; /** - * Tests for {@link PropertySourceConfigurationPropertySource}. + * Tests for {@link SpringConfigurationPropertySource}. * * @author Phillip Webb * @author Madhura Bhave */ -public class PropertySourceConfigurationPropertySourceTests { +public class SpringConfigurationPropertySourceTests { @Rule public ExpectedException thrown = ExpectedException.none(); @@ -46,16 +46,14 @@ public class PropertySourceConfigurationPropertySourceTests { public void createWhenPropertySourceIsNullShouldThrowException() throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("PropertySource must not be null"); - new PropertySourceConfigurationPropertySource(null, mock(PropertyMapper.class), - null); + new SpringConfigurationPropertySource(null, mock(PropertyMapper.class), null); } @Test public void createWhenMapperIsNullShouldThrowException() throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Mapper must not be null"); - new PropertySourceConfigurationPropertySource(mock(PropertySource.class), null, - null); + new SpringConfigurationPropertySource(mock(PropertySource.class), null, null); } @Test @@ -68,7 +66,7 @@ public class PropertySourceConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key2"); - PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource( + SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource( propertySource, mapper, null); assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); } @@ -82,7 +80,7 @@ public class PropertySourceConfigurationPropertySourceTests { ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key", (value) -> value.toString().replace("ue", "let")); - PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource( + SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource( propertySource, mapper, null); assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet"); } @@ -95,7 +93,7 @@ public class PropertySourceConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key"); - PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource( + SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource( propertySource, mapper, null); assertThat(adapter.getConfigurationProperty(name).getOrigin().toString()) .isEqualTo("\"key\" from property source \"test\""); @@ -110,7 +108,7 @@ public class PropertySourceConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key"); - PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource( + SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource( propertySource, mapper, null); assertThat(adapter.getConfigurationProperty(name).getOrigin().toString()) .isEqualTo("TestOrigin key"); @@ -121,12 +119,61 @@ public class PropertySourceConfigurationPropertySourceTests { Map source = new LinkedHashMap<>(); source.put("foo.bar", "value"); PropertySource propertySource = new MapPropertySource("test", source); - PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource( - propertySource, new DefaultPropertyMapper(), null); + SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource( + propertySource, DefaultPropertyMapper.INSTANCE, null); assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo"))) .isEmpty(); } + @Test + public void fromWhenPropertySourceIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Source must not be null"); + SpringConfigurationPropertySource.from(null); + } + + @Test + public void fromWhenNonEnumerableShouldReturnNonIterable() throws Exception { + PropertySource propertySource = new PropertySource("test", + new Object()) { + + @Override + public Object getProperty(String name) { + return null; + } + + }; + assertThat(SpringConfigurationPropertySource.from(propertySource)) + .isNotInstanceOf(IterableConfigurationPropertySource.class); + + } + + @Test + public void fromWhenEnumerableButRestrictedShouldReturnNonIterable() + throws Exception { + Map source = new LinkedHashMap() { + + @Override + public int size() { + throw new UnsupportedOperationException("Same as security restricted"); + } + + }; + PropertySource propertySource = new MapPropertySource("test", source); + assertThat(SpringConfigurationPropertySource.from(propertySource)) + .isNotInstanceOf(IterableConfigurationPropertySource.class); + } + + @Test + public void getWhenEnumerableShouldBeIterable() throws Exception { + Map source = new LinkedHashMap<>(); + source.put("fooBar", "Spring ${barBaz} ${bar-baz}"); + source.put("barBaz", "Boot"); + PropertySource propertySource = new MapPropertySource("test", source); + assertThat(SpringConfigurationPropertySource.from(propertySource)) + .isInstanceOf(IterableConfigurationPropertySource.class); + } + /** * Test {@link PropertySource} that's also a {@link OriginLookup}. */ diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java new file mode 100644 index 00000000000..786020ca758 --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java @@ -0,0 +1,135 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.context.properties.source; + +import java.util.Collections; +import java.util.Iterator; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.env.SystemEnvironmentPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringConfigurationPropertySources}. + * + * @author Phillip Webb + * @author Madhura Bhave + */ +public class SpringConfigurationPropertySourcesTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void createWhenPropertySourcesIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Sources must not be null"); + new SpringConfigurationPropertySources(null); + } + + @Test + public void shouldAdaptPropertySource() throws Exception { + MutablePropertySources sources = new MutablePropertySources(); + sources.addFirst(new MapPropertySource("test", + Collections.singletonMap("a", "b"))); + Iterator iterator = new SpringConfigurationPropertySources( + sources).iterator(); + ConfigurationPropertyName name = ConfigurationPropertyName.of("a"); + assertThat(iterator.next().getConfigurationProperty(name).getValue()) + .isEqualTo("b"); + assertThat(iterator.hasNext()).isFalse(); + } + + @Test + public void shouldAdaptSystemEnvironmentPropertySource() throws Exception { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new SystemEnvironmentPropertySource("system", + Collections.singletonMap("SERVER_PORT", "1234"))); + Iterator iterator = new SpringConfigurationPropertySources( + sources).iterator(); + ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); + assertThat(iterator.next().getConfigurationProperty(name).getValue()) + .isEqualTo("1234"); + assertThat(iterator.hasNext()).isFalse(); + } + + @Test + public void shouldAdaptMultiplePropertySources() throws Exception { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new SystemEnvironmentPropertySource("system", + Collections.singletonMap("SERVER_PORT", "1234"))); + sources.addLast(new MapPropertySource("test1", + Collections.singletonMap("server.po-rt", "4567"))); + sources.addLast(new MapPropertySource("test2", + Collections.singletonMap("a", "b"))); + Iterator iterator = new SpringConfigurationPropertySources( + sources).iterator(); + ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); + assertThat(iterator.next().getConfigurationProperty(name).getValue()) + .isEqualTo("1234"); + assertThat(iterator.next().getConfigurationProperty(name).getValue()) + .isEqualTo("4567"); + assertThat(iterator.next() + .getConfigurationProperty(ConfigurationPropertyName.of("a")).getValue()) + .isEqualTo("b"); + assertThat(iterator.hasNext()).isFalse(); + } + + @Test + public void shouldFlattenEnvironment() throws Exception { + StandardEnvironment environment = new StandardEnvironment(); + environment.getPropertySources().addFirst(new MapPropertySource("foo", + Collections.singletonMap("foo", "bar"))); + environment.getPropertySources().addFirst(new MapPropertySource("far", + Collections.singletonMap("far", "far"))); + MutablePropertySources sources = new MutablePropertySources(); + sources.addFirst(new PropertySource("env", environment) { + + @Override + public String getProperty(String key) { + return this.source.getProperty(key); + } + + }); + sources.addLast(new MapPropertySource("baz", + Collections.singletonMap("baz", "barf"))); + SpringConfigurationPropertySources configurationSources = new SpringConfigurationPropertySources( + sources); + assertThat(configurationSources.iterator()).hasSize(5); + } + + @Test + public void shouldTrackChanges() throws Exception { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new MapPropertySource("test1", + Collections.singletonMap("a", "b"))); + assertThat(new SpringConfigurationPropertySources(sources).iterator()).hasSize(1); + sources.addLast(new MapPropertySource("test2", + Collections.singletonMap("b", "c"))); + assertThat(new SpringConfigurationPropertySources(sources).iterator()).hasSize(2); + } + +} diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySourceTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java similarity index 85% rename from spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySourceTests.java rename to spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java index 7a7d63dd26e..238c200a9cd 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PropertySourceIterableConfigurationPropertySourceTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java @@ -33,12 +33,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; /** - * Tests for {@link PropertySourceIterableConfigurationPropertySource}. + * Tests for {@link SpringIterableConfigurationPropertySource}. * * @author Phillip Webb * @author Madhura Bhave */ -public class PropertySourceIterableConfigurationPropertySourceTests { +public class SpringIterableConfigurationPropertySourceTests { @Rule public ExpectedException thrown = ExpectedException.none(); @@ -47,15 +47,14 @@ public class PropertySourceIterableConfigurationPropertySourceTests { public void createWhenPropertySourceIsNullShouldThrowException() throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("PropertySource must not be null"); - new PropertySourceIterableConfigurationPropertySource(null, - mock(PropertyMapper.class)); + new SpringIterableConfigurationPropertySource(null, mock(PropertyMapper.class)); } @Test public void createWhenMapperIsNullShouldThrowException() throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Mapper must not be null"); - new PropertySourceIterableConfigurationPropertySource( + new SpringIterableConfigurationPropertySource( mock(EnumerablePropertySource.class), null); } @@ -72,7 +71,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { mapper.addFromPropertySource("key1", "my.key1"); mapper.addFromPropertySource("key2", "my.key2a", "my.key2b"); mapper.addFromPropertySource("key4", "my.key4"); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); assertThat(adapter.iterator()).extracting(Object::toString) .containsExactly("my.key1", "my.key2a", "my.key2b", "my.key4"); @@ -89,7 +88,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key2"); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); } @@ -105,7 +104,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); mapper.addFromPropertySource("key1", "my.missing"); mapper.addFromPropertySource("key2", "my.k-e-y"); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); @@ -121,7 +120,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key", (value) -> value.toString().replace("ue", "let")); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet"); } @@ -135,7 +134,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key"); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); assertThat(adapter.getConfigurationProperty(name).getOrigin().toString()) .isEqualTo("\"key\" from property source \"test\""); @@ -150,7 +149,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests { TestPropertyMapper mapper = new TestPropertyMapper(); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); mapper.addFromConfigurationProperty(name, "key"); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, mapper); assertThat(adapter.getConfigurationProperty(name).getOrigin().toString()) .isEqualTo("TestOrigin key"); @@ -163,8 +162,8 @@ public class PropertySourceIterableConfigurationPropertySourceTests { source.put("faf", "value"); EnumerablePropertySource propertySource = new OriginCapablePropertySource<>( new MapPropertySource("test", source)); - PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource( - propertySource, new DefaultPropertyMapper()); + SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( + propertySource, DefaultPropertyMapper.INSTANCE); assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo"))) .contains(true); assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("faf"))) diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapperTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapperTests.java index 7033b065485..8ce18f1992d 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapperTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapperTests.java @@ -36,11 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapperTests { - private SystemEnvironmentPropertyMapper mapper = new SystemEnvironmentPropertyMapper(); - @Override protected PropertyMapper getMapper() { - return this.mapper; + return SystemEnvironmentPropertyMapper.INSTANCE; } @Test @@ -75,7 +73,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper Map source = new LinkedHashMap<>(); source.put("SERVER__", "foo,bar,baz"); PropertySource propertySource = new MapPropertySource("test", source); - List mappings = this.mapper.map(propertySource, "SERVER__"); + List mappings = getMapper().map(propertySource, "SERVER__"); List result = new ArrayList<>(); for (PropertyMapping mapping : mappings) { Object value = propertySource.getProperty(mapping.getPropertySourceName()); @@ -91,7 +89,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper Map source = new LinkedHashMap<>(); source.put("SERVER__", "foo,bar,baz"); PropertySource propertySource = new MapPropertySource("test", source); - List mappings = this.mapper.map(propertySource, + List mappings = getMapper().map(propertySource, ConfigurationPropertyName.of("server[1]")); List result = new ArrayList<>(); for (PropertyMapping mapping : mappings) { @@ -108,7 +106,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper public void underscoreShouldNotMapToEmptyString() throws Exception { Map source = new LinkedHashMap<>(); PropertySource propertySource = new MapPropertySource("test", source); - List mappings = this.mapper.map(propertySource, "_"); + List mappings = getMapper().map(propertySource, "_"); boolean applicable = false; for (PropertyMapping mapping : mappings) { applicable = mapping.isApplicable(ConfigurationPropertyName.of("")); @@ -120,7 +118,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper public void underscoreWithWhitespaceShouldNotMapToEmptyString() throws Exception { Map source = new LinkedHashMap<>(); PropertySource propertySource = new MapPropertySource("test", source); - List mappings = this.mapper.map(propertySource, " _"); + List mappings = getMapper().map(propertySource, " _"); boolean applicable = false; for (PropertyMapping mapping : mappings) { applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));