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
This commit is contained in:
parent
133f11df2f
commit
fa4de13519
|
|
@ -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.bind.Binder;
|
||||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||||
import org.springframework.boot.info.InfoProperties;
|
import org.springframework.boot.info.InfoProperties;
|
||||||
import org.springframework.core.env.MutablePropertySources;
|
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
|
@ -93,9 +92,7 @@ public abstract class InfoPropertiesInfoContributor<T extends InfoProperties>
|
||||||
* @return the raw content
|
* @return the raw content
|
||||||
*/
|
*/
|
||||||
protected Map<String, Object> extractContent(PropertySource<?> propertySource) {
|
protected Map<String, Object> extractContent(PropertySource<?> propertySource) {
|
||||||
MutablePropertySources sources = new MutablePropertySources();
|
return new Binder(ConfigurationPropertySources.from(propertySource))
|
||||||
sources.addFirst(propertySource);
|
|
||||||
return new Binder(ConfigurationPropertySources.get(sources))
|
|
||||||
.bind("", STRING_OBJECT_MAP).orElseGet(LinkedHashMap::new);
|
.bind("", STRING_OBJECT_MAP).orElseGet(LinkedHashMap::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
|
@ -320,9 +321,8 @@ public class EndpointAutoConfigurationTests {
|
||||||
if (!location.exists()) {
|
if (!location.exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MapConfigurationPropertySource source = new MapConfigurationPropertySource(
|
Properties properties = PropertiesLoaderUtils.loadProperties(location);
|
||||||
PropertiesLoaderUtils.loadProperties(location));
|
new Binder(new MapConfigurationPropertySource(properties)).bind("info",
|
||||||
new Binder(source).bind("info",
|
|
||||||
Bindable.of(STRING_OBJECT_MAP).withExistingValue(this.content));
|
Bindable.of(STRING_OBJECT_MAP).withExistingValue(this.content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.WebApplicationType;
|
import org.springframework.boot.WebApplicationType;
|
||||||
import org.springframework.boot.context.properties.bind.Bindable;
|
import org.springframework.boot.context.properties.bind.Bindable;
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
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.context.properties.source.MapConfigurationPropertySource;
|
||||||
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
|
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
|
||||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
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();
|
return binder.bind("server.port", Bindable.of(String.class)).isBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapConfigurationPropertySource convertToConfigurationPropertySource(
|
private ConfigurationPropertySource convertToConfigurationPropertySource(
|
||||||
List<String> properties) {
|
List<String> properties) {
|
||||||
String[] array = properties.toArray(new String[properties.size()]);
|
String[] array = properties.toArray(new String[properties.size()]);
|
||||||
return new MapConfigurationPropertySource(
|
return new MapConfigurationPropertySource(
|
||||||
|
|
|
||||||
|
|
@ -480,9 +480,7 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleProfileProperties(PropertySource<?> propertySource) {
|
private void handleProfileProperties(PropertySource<?> propertySource) {
|
||||||
MutablePropertySources propertySources = new MutablePropertySources();
|
Binder binder = new Binder(ConfigurationPropertySources.from(propertySource),
|
||||||
propertySources.addFirst(propertySource);
|
|
||||||
Binder binder = new Binder(ConfigurationPropertySources.get(propertySources),
|
|
||||||
new PropertySourcesPlaceholdersResolver(this.environment));
|
new PropertySourcesPlaceholdersResolver(this.environment));
|
||||||
Set<Profile> active = getProfiles(binder, "spring.profiles.active");
|
Set<Profile> active = getProfiles(binder, "spring.profiles.active");
|
||||||
Set<Profile> include = getProfiles(binder, "spring.profiles.include");
|
Set<Profile> include = getProfiles(binder, "spring.profiles.include");
|
||||||
|
|
|
||||||
|
|
@ -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.IgnoreErrorsBindHandler;
|
||||||
import org.springframework.boot.context.properties.bind.handler.NoUnboundElementsBindHandler;
|
import org.springframework.boot.context.properties.bind.handler.NoUnboundElementsBindHandler;
|
||||||
import org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;
|
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.context.properties.source.ConfigurationPropertySources;
|
||||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
@ -59,6 +60,7 @@ import org.springframework.core.convert.converter.GenericConverter;
|
||||||
import org.springframework.core.convert.support.DefaultConversionService;
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.env.PropertySources;
|
import org.springframework.core.env.PropertySources;
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -95,7 +97,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
|
|
||||||
private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData();
|
private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData();
|
||||||
|
|
||||||
private PropertySources propertySources;
|
private Iterable<PropertySource<?>> propertySources;
|
||||||
|
|
||||||
private Validator validator;
|
private Validator validator;
|
||||||
|
|
||||||
|
|
@ -117,7 +119,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
|
|
||||||
private int order = Ordered.HIGHEST_PRECEDENCE + 1;
|
private int order = Ordered.HIGHEST_PRECEDENCE + 1;
|
||||||
|
|
||||||
private ConfigurationPropertySources configurationSources;
|
private Iterable<ConfigurationPropertySource> configurationSources;
|
||||||
|
|
||||||
private Binder binder;
|
private Binder binder;
|
||||||
|
|
||||||
|
|
@ -164,7 +166,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
* Set the property sources to bind.
|
* Set the property sources to bind.
|
||||||
* @param propertySources the property sources
|
* @param propertySources the property sources
|
||||||
*/
|
*/
|
||||||
public void setPropertySources(PropertySources propertySources) {
|
public void setPropertySources(Iterable<PropertySource<?>> propertySources) {
|
||||||
this.propertySources = propertySources;
|
this.propertySources = propertySources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,7 +223,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
ConversionService.class);
|
ConversionService.class);
|
||||||
}
|
}
|
||||||
this.configurationSources = ConfigurationPropertySources
|
this.configurationSources = ConfigurationPropertySources
|
||||||
.get(this.propertySources);
|
.from(this.propertySources);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -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.ConfigurationPropertySource;
|
||||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -331,13 +330,12 @@ public class Binder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link Binder} instance from the specified environment.
|
* 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
|
* @return a {@link Binder} instance
|
||||||
*/
|
*/
|
||||||
public static Binder get(Environment environment) {
|
public static Binder get(Environment environment) {
|
||||||
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
|
return new Binder(ConfigurationPropertySources.get(environment),
|
||||||
return new Binder(
|
|
||||||
ConfigurationPropertySources.get((ConfigurableEnvironment) environment),
|
|
||||||
new PropertySourcesPlaceholdersResolver(environment));
|
new PropertySourcesPlaceholdersResolver(environment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import org.springframework.util.SystemPropertyUtils;
|
||||||
*/
|
*/
|
||||||
public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver {
|
public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver {
|
||||||
|
|
||||||
private final PropertySources sources;
|
private final Iterable<PropertySource<?>> sources;
|
||||||
|
|
||||||
private final PropertyPlaceholderHelper helper;
|
private final PropertyPlaceholderHelper helper;
|
||||||
|
|
||||||
|
|
@ -41,11 +41,11 @@ public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver
|
||||||
this(getSources(environment), null);
|
this(getSources(environment), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertySourcesPlaceholdersResolver(PropertySources sources) {
|
public PropertySourcesPlaceholdersResolver(Iterable<PropertySource<?>> sources) {
|
||||||
this(sources, null);
|
this(sources, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertySourcesPlaceholdersResolver(PropertySources sources,
|
public PropertySourcesPlaceholdersResolver(Iterable<PropertySource<?>> sources,
|
||||||
PropertyPlaceholderHelper helper) {
|
PropertyPlaceholderHelper helper) {
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
this.helper = (helper != null ? helper
|
this.helper = (helper != null ? helper
|
||||||
|
|
|
||||||
|
|
@ -16,72 +16,115 @@
|
||||||
|
|
||||||
package org.springframework.boot.context.properties.source;
|
package org.springframework.boot.context.properties.source;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.stream.Collectors;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import org.springframework.boot.env.RandomValuePropertySource;
|
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
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.MutablePropertySources;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.env.PropertySource.StubPropertySource;
|
import org.springframework.core.env.PropertySource.StubPropertySource;
|
||||||
import org.springframework.core.env.PropertySources;
|
|
||||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
||||||
import org.springframework.core.env.SystemEnvironmentPropertySource;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A managed set of {@link ConfigurationPropertySource} instances, usually adapted from
|
* Provides access to {@link ConfigurationPropertySource ConfigurationPropertySources}.
|
||||||
* Spring's {@link PropertySources}.
|
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
* @see #attach(MutablePropertySources)
|
|
||||||
* @see #get(PropertySources)
|
|
||||||
*/
|
*/
|
||||||
public class ConfigurationPropertySources
|
public final class ConfigurationPropertySources {
|
||||||
implements Iterable<ConfigurationPropertySource> {
|
|
||||||
|
|
||||||
private static final ConfigurationPropertyName RANDOM = ConfigurationPropertyName
|
|
||||||
.of("random");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the {@link PropertySource} {@link #adapt adapter}.
|
* The name of the {@link PropertySource} {@link #adapt adapter}.
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_SOURCE_NAME = "configurationProperties";
|
private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";
|
||||||
|
|
||||||
private final PropertySources propertySources;
|
private ConfigurationPropertySources() {
|
||||||
|
}
|
||||||
private final Map<PropertySource<?>, ConfigurationPropertySource> adapters = new WeakHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link ConfigurationPropertySources} instance.
|
* Attach a {@link ConfigurationPropertySource} support to the specified
|
||||||
* @param propertySources the property sources to expose
|
* {@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}.
|
||||||
|
* <p>
|
||||||
|
* 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) {
|
public static void attach(Environment environment) {
|
||||||
Assert.notNull(propertySources, "PropertySources must not be null");
|
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
|
||||||
this.propertySources = propertySources;
|
MutablePropertySources sources = ((ConfigurableEnvironment) environment)
|
||||||
|
.getPropertySources();
|
||||||
|
if (!sources.contains(ATTACHED_PROPERTY_SOURCE_NAME)) {
|
||||||
|
sources.addFirst(new ConfigurationPropertySourcesPropertySource(
|
||||||
|
ATTACHED_PROPERTY_SOURCE_NAME,
|
||||||
|
new SpringConfigurationPropertySources(sources)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Iterator<ConfigurationPropertySource> iterator() {
|
* Return a set of {@link ConfigurationPropertySource} instances that have previously
|
||||||
return streamPropertySources(this.propertySources)
|
* been {@link #attach(Environment) attached} to the {@link Environment}.
|
||||||
.filter(s -> !(s instanceof ConfigurationPropertySourcesPropertySource))
|
* @param environment the source environment (must be an instance of
|
||||||
.map(this::adapt).iterator();
|
* {@link ConfigurableEnvironment})
|
||||||
|
* @return an iterable set of configuration property sources
|
||||||
|
* @throws IllegalStateException if not configuration property sources have been
|
||||||
|
* attached
|
||||||
|
*/
|
||||||
|
public static Iterable<ConfigurationPropertySource> 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 attached.getSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<PropertySource<?>> streamPropertySources(PropertySources sources) {
|
/**
|
||||||
return StreamSupport.stream(sources.spliterator(), false).flatMap(this::flatten)
|
* Return {@link Iterable} containing a single new {@link ConfigurationPropertySource}
|
||||||
.filter(this::notStubSource);
|
* 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 Iterable<ConfigurationPropertySource> from(PropertySource<?> source) {
|
||||||
|
return Collections.singleton(SpringConfigurationPropertySource.from(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<PropertySource<?>> flatten(PropertySource<?> source) {
|
/**
|
||||||
|
* Return {@link Iterable} containing new {@link ConfigurationPropertySource}
|
||||||
|
* instances adapted from the given Spring {@link PropertySource PropertySources}.
|
||||||
|
* <p>
|
||||||
|
* 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 Iterable<ConfigurationPropertySource> from(
|
||||||
|
Iterable<PropertySource<?>> sources) {
|
||||||
|
return streamPropertySources(sources).map(SpringConfigurationPropertySource::from)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<PropertySource<?>> streamPropertySources(
|
||||||
|
Iterable<PropertySource<?>> sources) {
|
||||||
|
return StreamSupport.stream(sources.spliterator(), false)
|
||||||
|
.flatMap(ConfigurationPropertySources::flatten)
|
||||||
|
.filter(ConfigurationPropertySources::isIncluded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<PropertySource<?>> flatten(PropertySource<?> source) {
|
||||||
if (source.getSource() instanceof ConfigurableEnvironment) {
|
if (source.getSource() instanceof ConfigurableEnvironment) {
|
||||||
return streamPropertySources(
|
return streamPropertySources(
|
||||||
((ConfigurableEnvironment) source.getSource()).getPropertySources());
|
((ConfigurableEnvironment) source.getSource()).getPropertySources());
|
||||||
|
|
@ -89,124 +132,9 @@ public class ConfigurationPropertySources
|
||||||
return Stream.of(source);
|
return Stream.of(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean notStubSource(PropertySource<?> source) {
|
private static boolean isIncluded(PropertySource<?> source) {
|
||||||
return !(source instanceof StubPropertySource);
|
return !(source instanceof StubPropertySource)
|
||||||
}
|
&& !(source instanceof ConfigurationPropertySourcesPropertySource);
|
||||||
|
|
||||||
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<ConfigurationPropertyName, Optional<Boolean>> getContainsDescendantOfMethod(
|
|
||||||
PropertySource<?> source) {
|
|
||||||
if (source instanceof RandomValuePropertySource) {
|
|
||||||
return (name) -> Optional
|
|
||||||
.of(name.isAncestorOf(RANDOM) || name.equals(RANDOM));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public static ConfigurationPropertySources attach(
|
|
||||||
ConfigurableEnvironment environment) {
|
|
||||||
return attach(environment.getPropertySources());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public static ConfigurationPropertySources attach(
|
|
||||||
MutablePropertySources propertySources) {
|
|
||||||
ConfigurationPropertySources adapted = new ConfigurationPropertySources(
|
|
||||||
propertySources);
|
|
||||||
propertySources.addFirst(new ConfigurationPropertySourcesPropertySource(
|
|
||||||
PROPERTY_SOURCE_NAME, adapted));
|
|
||||||
return adapted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
return new ConfigurationPropertySources(propertySources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.context.properties.source;
|
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.Origin;
|
||||||
import org.springframework.boot.origin.OriginLookup;
|
import org.springframework.boot.origin.OriginLookup;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
@ -70,10 +66,14 @@ class ConfigurationPropertySourcesPropertySource
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Stream<ConfigurationPropertySource> sources = StreamSupport
|
for (ConfigurationPropertySource configurationPropertySource : getSource()) {
|
||||||
.stream(getSource().spliterator(), false);
|
ConfigurationProperty configurationProperty = configurationPropertySource
|
||||||
return sources.map(source -> source.getConfigurationProperty(name))
|
.getConfigurationProperty(name);
|
||||||
.filter(Objects::nonNull).findFirst().orElse(null);
|
if (configurationProperty != null) {
|
||||||
|
return configurationProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,10 @@
|
||||||
package org.springframework.boot.context.properties.source;
|
package org.springframework.boot.context.properties.source;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default {@link PropertyMapper} implementation. Names are mapped by removing invalid
|
* Default {@link PropertyMapper} implementation. Names are mapped by removing invalid
|
||||||
|
|
@ -31,36 +30,48 @@ import org.springframework.core.env.PropertySource;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @see PropertyMapper
|
* @see PropertyMapper
|
||||||
* @see PropertySourceConfigurationPropertySource
|
* @see SpringConfigurationPropertySource
|
||||||
*/
|
*/
|
||||||
class DefaultPropertyMapper implements PropertyMapper {
|
final class DefaultPropertyMapper implements PropertyMapper {
|
||||||
|
|
||||||
public static final PropertyMapper INSTANCE = new DefaultPropertyMapper();
|
public static final PropertyMapper INSTANCE = new DefaultPropertyMapper();
|
||||||
|
|
||||||
private final Cache<ConfigurationPropertyName> configurationPropertySourceCache = new Cache<>();
|
private LastMapping<ConfigurationPropertyName> lastMappedConfigurationPropertyName;
|
||||||
|
|
||||||
private final Cache<String> propertySourceCache = new Cache<>();
|
private LastMapping<String> lastMappedPropertyName;
|
||||||
|
|
||||||
private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder();
|
private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder();
|
||||||
|
|
||||||
|
private DefaultPropertyMapper() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||||
ConfigurationPropertyName configurationPropertyName) {
|
ConfigurationPropertyName configurationPropertyName) {
|
||||||
List<PropertyMapping> mapping = this.configurationPropertySourceCache
|
// Use a local copy in case another thread changes things
|
||||||
.get(configurationPropertyName);
|
LastMapping<ConfigurationPropertyName> last = this.lastMappedConfigurationPropertyName;
|
||||||
if (mapping == null) {
|
if (last != null && last.isFrom(configurationPropertyName)) {
|
||||||
String convertedName = configurationPropertyName.toString();
|
return last.getMapping();
|
||||||
mapping = Collections.singletonList(
|
|
||||||
new PropertyMapping(convertedName, configurationPropertyName));
|
|
||||||
this.configurationPropertySourceCache.put(configurationPropertyName, mapping);
|
|
||||||
}
|
}
|
||||||
|
String convertedName = configurationPropertyName.toString();
|
||||||
|
List<PropertyMapping> mapping = Collections.singletonList(
|
||||||
|
new PropertyMapping(convertedName, configurationPropertyName));
|
||||||
|
this.lastMappedConfigurationPropertyName = new LastMapping<>(
|
||||||
|
configurationPropertyName, mapping);
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||||
String propertySourceName) {
|
String propertySourceName) {
|
||||||
return this.propertySourceCache.computeIfAbsent(propertySourceName, this::tryMap);
|
// Use a local copy in case another thread changes things
|
||||||
|
LastMapping<String> last = this.lastMappedPropertyName;
|
||||||
|
if (last != null && last.isFrom(propertySourceName)) {
|
||||||
|
return last.getMapping();
|
||||||
|
}
|
||||||
|
List<PropertyMapping> mapping = tryMap(propertySourceName);
|
||||||
|
this.lastMappedPropertyName = new LastMapping<>(propertySourceName, mapping);
|
||||||
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PropertyMapping> tryMap(String propertySourceName) {
|
private List<PropertyMapping> tryMap(String propertySourceName) {
|
||||||
|
|
@ -75,23 +86,23 @@ class DefaultPropertyMapper implements PropertyMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Cache<K> extends LinkedHashMap<K, List<PropertyMapping>> {
|
private static class LastMapping<T> {
|
||||||
|
|
||||||
private final int capacity;
|
private final T from;
|
||||||
|
|
||||||
Cache() {
|
private final List<PropertyMapping> mapping;
|
||||||
this(1);
|
|
||||||
|
LastMapping(T from, List<PropertyMapping> mapping) {
|
||||||
|
this.from = from;
|
||||||
|
this.mapping = mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache(int capacity) {
|
public boolean isFrom(T from) {
|
||||||
super(capacity, (float) 0.75, true);
|
return ObjectUtils.nullSafeEquals(from, this.from);
|
||||||
this.capacity = capacity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public List<PropertyMapping> getMapping() {
|
||||||
protected boolean removeEldestEntry(Map.Entry<K, List<PropertyMapping>> eldest) {
|
return this.mapping;
|
||||||
return size() > this.capacity;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import org.springframework.util.Assert;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
*/
|
||||||
public class MapConfigurationPropertySource
|
public class MapConfigurationPropertySource
|
||||||
implements IterableConfigurationPropertySource {
|
implements IterableConfigurationPropertySource {
|
||||||
|
|
@ -54,9 +53,9 @@ public class MapConfigurationPropertySource
|
||||||
*/
|
*/
|
||||||
public MapConfigurationPropertySource(Map<?, ?> map) {
|
public MapConfigurationPropertySource(Map<?, ?> map) {
|
||||||
this.source = new LinkedHashMap<>();
|
this.source = new LinkedHashMap<>();
|
||||||
this.delegate = new PropertySourceIterableConfigurationPropertySource(
|
this.delegate = new SpringIterableConfigurationPropertySource(
|
||||||
new MapPropertySource("source", this.source),
|
new MapPropertySource("source", this.source),
|
||||||
new DefaultPropertyMapper());
|
DefaultPropertyMapper.INSTANCE);
|
||||||
putAll(map);
|
putAll(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,16 +27,16 @@ import org.springframework.core.env.PropertySource;
|
||||||
* <P>
|
* <P>
|
||||||
* Mappings should be provided for both {@link ConfigurationPropertyName
|
* Mappings should be provided for both {@link ConfigurationPropertyName
|
||||||
* ConfigurationPropertyName} types and {@code String} based names. This allows the
|
* 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}
|
* (i.e. map the {@link ConfigurationPropertyName} directly to the {@link PropertySource}
|
||||||
* name) before falling back to {@link EnumerablePropertySource enumerating} property
|
* name) before falling back to {@link EnumerablePropertySource enumerating} property
|
||||||
* names, mapping them to a {@link ConfigurationPropertyName} and checking for
|
* names, mapping them to a {@link ConfigurationPropertyName} and checking for
|
||||||
* {@link PropertyMapping#isApplicable(ConfigurationPropertyName) applicability}. See
|
* {@link PropertyMapping#isApplicable(ConfigurationPropertyName) applicability}. See
|
||||||
* {@link PropertySourceConfigurationPropertySource} for more details.
|
* {@link SpringConfigurationPropertySource} for more details.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @see PropertySourceConfigurationPropertySource
|
* @see SpringConfigurationPropertySource
|
||||||
*/
|
*/
|
||||||
interface PropertyMapper {
|
interface PropertyMapper {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import org.springframework.core.env.PropertySource;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @see PropertySourceConfigurationPropertySource
|
* @see SpringConfigurationPropertySource
|
||||||
*/
|
*/
|
||||||
class PropertyMapping {
|
class PropertyMapping {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,17 @@ package org.springframework.boot.context.properties.source;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.springframework.boot.env.RandomValuePropertySource;
|
||||||
import org.springframework.boot.origin.Origin;
|
import org.springframework.boot.origin.Origin;
|
||||||
import org.springframework.boot.origin.PropertySourceOrigin;
|
import org.springframework.boot.origin.PropertySourceOrigin;
|
||||||
import org.springframework.core.env.EnumerablePropertySource;
|
import org.springframework.core.env.EnumerablePropertySource;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.env.SystemEnvironmentPropertySource;
|
||||||
import org.springframework.util.Assert;
|
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
|
* {@link ConfigurationPropertyName} to one or more {@code String} based names. This
|
||||||
* allows fast property resolution for well formed property sources.
|
* allows fast property resolution for well formed property sources.
|
||||||
* <p>
|
* <p>
|
||||||
* If at all possible the {@link PropertySourceIterableConfigurationPropertySource} should
|
* When possible the {@link SpringIterableConfigurationPropertySource} will be used in
|
||||||
* be used in preference to this implementation since it supports "relaxed" style
|
* preference to this implementation since it supports full "relaxed" style resolution.
|
||||||
* resolution.
|
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @see #from(PropertySource)
|
||||||
* @see PropertyMapper
|
* @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;
|
private final PropertySource<?> propertySource;
|
||||||
|
|
||||||
|
|
@ -59,21 +65,21 @@ class PropertySourceConfigurationPropertySource implements ConfigurationProperty
|
||||||
private final Function<ConfigurationPropertyName, Optional<Boolean>> containsDescendantOfMethod;
|
private final Function<ConfigurationPropertyName, Optional<Boolean>> containsDescendantOfMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link PropertySourceConfigurationPropertySource} implementation.
|
* Create a new {@link SpringConfigurationPropertySource} implementation.
|
||||||
* @param propertySource the source property source
|
* @param propertySource the source property source
|
||||||
* @param mapper the property mapper
|
* @param mapper the property mapper
|
||||||
* @param containsDescendantOfMethod function used to implement
|
* @param containsDescendantOfMethod function used to implement
|
||||||
* {@link #containsDescendantOf(ConfigurationPropertyName)} (may be {@code null})
|
* {@link #containsDescendantOf(ConfigurationPropertyName)} (may be {@code null})
|
||||||
*/
|
*/
|
||||||
PropertySourceConfigurationPropertySource(PropertySource<?> propertySource,
|
SpringConfigurationPropertySource(PropertySource<?> propertySource,
|
||||||
PropertyMapper mapper,
|
PropertyMapper mapper,
|
||||||
Function<ConfigurationPropertyName, Optional<Boolean>> containsDescendantOfMethod) {
|
Function<ConfigurationPropertyName, Optional<Boolean>> containsDescendantOfMethod) {
|
||||||
Assert.notNull(propertySource, "PropertySource must not be null");
|
Assert.notNull(propertySource, "PropertySource must not be null");
|
||||||
Assert.notNull(mapper, "Mapper must not be null");
|
Assert.notNull(mapper, "Mapper must not be null");
|
||||||
this.propertySource = propertySource;
|
this.propertySource = propertySource;
|
||||||
this.mapper = new ExceptionSwallowingPropertyMapper(mapper);
|
this.mapper = new ExceptionSwallowingPropertyMapper(mapper);
|
||||||
this.containsDescendantOfMethod = (containsDescendantOfMethod != null ? containsDescendantOfMethod
|
this.containsDescendantOfMethod = (containsDescendantOfMethod != null
|
||||||
: (n) -> Optional.empty());
|
? containsDescendantOfMethod : (n) -> Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -120,6 +126,62 @@ class PropertySourceConfigurationPropertySource implements ConfigurationProperty
|
||||||
return this.propertySource.toString();
|
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<ConfigurationPropertyName, Optional<Boolean>> 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.
|
* {@link PropertyMapper} that swallows exceptions when the mapping fails.
|
||||||
*/
|
*/
|
||||||
|
|
@ -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<ConfigurationPropertySource> {
|
||||||
|
|
||||||
|
private final MutablePropertySources sources;
|
||||||
|
|
||||||
|
private volatile PropertySourcesKey lastKey;
|
||||||
|
|
||||||
|
private volatile List<ConfigurationPropertySource> adaptedSources;
|
||||||
|
|
||||||
|
SpringConfigurationPropertySources(MutablePropertySources sources) {
|
||||||
|
Assert.notNull(sources, "Sources must not be null");
|
||||||
|
this.sources = sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<ConfigurationPropertySource> 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<PropertySource<?>> streamPropertySources(
|
||||||
|
Iterable<PropertySource<?>> sources) {
|
||||||
|
return StreamSupport.stream(sources.spliterator(), false).flatMap(this::flatten)
|
||||||
|
.filter(this::isIncluded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<PropertySource<?>> 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<PropertySourceKey> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -31,21 +31,24 @@ import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ConfigurationPropertySource} backed by a {@link EnumerablePropertySource}.
|
* {@link ConfigurationPropertySource} backed by a {@link EnumerablePropertySource}.
|
||||||
* Extends {@link PropertySourceConfigurationPropertySource} with full "relaxed" mapping
|
* Extends {@link SpringConfigurationPropertySource} with full "relaxed" mapping support.
|
||||||
* support. In order to use this adapter the underlying {@link PropertySource} must be
|
* In order to use this adapter the underlying {@link PropertySource} must be fully
|
||||||
* fully enumerable. A security restricted {@link SystemEnvironmentPropertySource} cannot
|
* enumerable. A security restricted {@link SystemEnvironmentPropertySource} cannot be
|
||||||
* be adapted.
|
* adapted.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @see PropertyMapper
|
* @see PropertyMapper
|
||||||
*/
|
*/
|
||||||
class PropertySourceIterableConfigurationPropertySource
|
class SpringIterableConfigurationPropertySource extends SpringConfigurationPropertySource
|
||||||
extends PropertySourceConfigurationPropertySource
|
|
||||||
implements IterableConfigurationPropertySource {
|
implements IterableConfigurationPropertySource {
|
||||||
|
|
||||||
PropertySourceIterableConfigurationPropertySource(
|
private volatile Object cacheKey;
|
||||||
EnumerablePropertySource<?> propertySource, PropertyMapper mapper) {
|
|
||||||
|
private volatile Cache cache;
|
||||||
|
|
||||||
|
SpringIterableConfigurationPropertySource(EnumerablePropertySource<?> propertySource,
|
||||||
|
PropertyMapper mapper) {
|
||||||
super(propertySource, mapper, null);
|
super(propertySource, mapper, null);
|
||||||
assertEnumerablePropertySource(propertySource);
|
assertEnumerablePropertySource(propertySource);
|
||||||
}
|
}
|
||||||
|
|
@ -63,10 +66,6 @@ class PropertySourceIterableConfigurationPropertySource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile Object cacheKey;
|
|
||||||
|
|
||||||
private volatile Cache cache;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurationProperty getConfigurationProperty(
|
public ConfigurationProperty getConfigurationProperty(
|
||||||
ConfigurationPropertyName name) {
|
ConfigurationPropertyName name) {
|
||||||
|
|
@ -41,15 +41,18 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @see PropertyMapper
|
* @see PropertyMapper
|
||||||
* @see PropertySourceConfigurationPropertySource
|
* @see SpringConfigurationPropertySource
|
||||||
*/
|
*/
|
||||||
class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
final class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
||||||
|
|
||||||
public static final PropertyMapper INSTANCE = new SystemEnvironmentPropertyMapper();
|
public static final PropertyMapper INSTANCE = new SystemEnvironmentPropertyMapper();
|
||||||
|
|
||||||
private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder(
|
private final ConfigurationPropertyNameBuilder nameBuilder = new ConfigurationPropertyNameBuilder(
|
||||||
this::createElement);
|
this::createElement);
|
||||||
|
|
||||||
|
private SystemEnvironmentPropertyMapper() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||||
String propertySourceName) {
|
String propertySourceName) {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEven
|
||||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
import org.springframework.boot.context.event.ApplicationStartingEvent;
|
import org.springframework.boot.context.event.ApplicationStartingEvent;
|
||||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
|
||||||
import org.springframework.boot.testutil.InternalOutputCapture;
|
import org.springframework.boot.testutil.InternalOutputCapture;
|
||||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||||
|
|
@ -868,8 +867,7 @@ public class SpringApplicationTests {
|
||||||
assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bar");
|
assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bar");
|
||||||
Iterator<PropertySource<?>> iterator = this.context.getEnvironment()
|
Iterator<PropertySource<?>> iterator = this.context.getEnvironment()
|
||||||
.getPropertySources().iterator();
|
.getPropertySources().iterator();
|
||||||
assertThat(iterator.next().getName())
|
assertThat(iterator.next().getName()).isEqualTo("configurationProperties");
|
||||||
.isEqualTo(ConfigurationPropertySources.PROPERTY_SOURCE_NAME);
|
|
||||||
assertThat(iterator.next().getName()).isEqualTo(
|
assertThat(iterator.next().getName()).isEqualTo(
|
||||||
TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);
|
TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ public class LoggingApplicationListenerTests {
|
||||||
new File("target/foo.log").delete();
|
new File("target/foo.log").delete();
|
||||||
new File(tmpDir() + "/spring.log").delete();
|
new File(tmpDir() + "/spring.log").delete();
|
||||||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||||
ConfigurationPropertySources.attach(environment.getPropertySources());
|
ConfigurationPropertySources.attach(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.boot.context.properties.source;
|
package org.springframework.boot.context.properties.source;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -25,7 +24,7 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
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.Environment;
|
||||||
import org.springframework.core.env.MapPropertySource;
|
import org.springframework.core.env.MapPropertySource;
|
||||||
import org.springframework.core.env.MutablePropertySources;
|
import org.springframework.core.env.MutablePropertySources;
|
||||||
|
|
@ -41,169 +40,47 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* Tests for {@link ConfigurationPropertySources}.
|
* Tests for {@link ConfigurationPropertySources}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
|
||||||
*/
|
*/
|
||||||
public class ConfigurationPropertySourcesTests {
|
public class ConfigurationPropertySourcesTests {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
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.<String, Object>singletonMap("a", "b")));
|
|
||||||
Iterator<ConfigurationPropertySource> 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.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
|
||||||
Iterator<ConfigurationPropertySource> 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.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
|
||||||
sources.addLast(new MapPropertySource("test1",
|
|
||||||
Collections.<String, Object>singletonMap("server.po-rt", "4567")));
|
|
||||||
sources.addLast(new MapPropertySource("test2",
|
|
||||||
Collections.<String, Object>singletonMap("a", "b")));
|
|
||||||
Iterator<ConfigurationPropertySource> 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
|
@Test
|
||||||
public void attachShouldAddAdapterAtBeginning() throws Exception {
|
public void attachShouldAddAdapterAtBeginning() throws Exception {
|
||||||
MutablePropertySources sources = new MutablePropertySources();
|
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||||
|
MutablePropertySources sources = environment.getPropertySources();
|
||||||
sources.addLast(new SystemEnvironmentPropertySource("system",
|
sources.addLast(new SystemEnvironmentPropertySource("system",
|
||||||
Collections.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
Collections.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
||||||
sources.addLast(new MapPropertySource("config",
|
sources.addLast(new MapPropertySource("config",
|
||||||
Collections.<String, Object>singletonMap("server.port", "4568")));
|
Collections.<String, Object>singletonMap("server.port", "4568")));
|
||||||
assertThat(sources.size()).isEqualTo(2);
|
int size = sources.size();
|
||||||
ConfigurationPropertySources.attach(sources);
|
ConfigurationPropertySources.attach(environment);
|
||||||
|
assertThat(sources.size()).isEqualTo(size + 1);
|
||||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
|
PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
|
||||||
assertThat(resolver.getProperty("server.port")).isEqualTo("1234");
|
assertThat(resolver.getProperty("server.port")).isEqualTo("1234");
|
||||||
assertThat(sources.size()).isEqualTo(3);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenNotAttachedShouldReturnAdapted() throws Exception {
|
||||||
|
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||||
|
assertThat(ConfigurationPropertySources.get(environment)).isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getWhenAttachedShouldReturnAttached() throws Exception {
|
public void getWhenAttachedShouldReturnAttached() throws Exception {
|
||||||
MutablePropertySources sources = new MutablePropertySources();
|
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||||
|
MutablePropertySources sources = environment.getPropertySources();
|
||||||
sources.addFirst(new MapPropertySource("test",
|
sources.addFirst(new MapPropertySource("test",
|
||||||
Collections.<String, Object>singletonMap("a", "b")));
|
Collections.<String, Object>singletonMap("a", "b")));
|
||||||
ConfigurationPropertySources attached = ConfigurationPropertySources
|
int expectedSize = sources.size();
|
||||||
.attach(sources);
|
ConfigurationPropertySources.attach(environment);
|
||||||
assertThat(ConfigurationPropertySources.get(sources)).isSameAs(attached);
|
assertThat(ConfigurationPropertySources.get(environment)).hasSize(expectedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getWhenNotAttachedShouldReturnNew() throws Exception {
|
public void environmentProperyExpansionShouldWorkWhenAttached() throws Exception {
|
||||||
MutablePropertySources sources = new MutablePropertySources();
|
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||||
sources.addFirst(new MapPropertySource("test",
|
|
||||||
Collections.<String, Object>singletonMap("a", "b")));
|
|
||||||
assertThat(ConfigurationPropertySources.get(sources)).isNotNull();
|
|
||||||
assertThat(sources.size()).isEqualTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getWhenNonEnumerableShouldNotBeIterable() throws Exception {
|
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
|
||||||
Map<String, Object> source = new LinkedHashMap<String, Object>() {
|
|
||||||
|
|
||||||
@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<Object>("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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getWhenEnumerableShouldBeIterable() throws Exception {
|
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
|
||||||
Map<String, Object> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void environmentPropertyExpansionShouldWorkWhenAttached() throws Exception {
|
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
source.put("fooBar", "Spring ${barBaz} ${bar-baz}");
|
source.put("fooBar", "Spring ${barBaz} ${bar-baz}");
|
||||||
source.put("barBaz", "Boot");
|
source.put("barBaz", "Boot");
|
||||||
|
|
@ -214,7 +91,18 @@ public class ConfigurationPropertySourcesTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void environmentSourceShouldBeFlattened() throws Exception {
|
public void fromPropertySourceShouldReturnSpringConfigurationPropertySource()
|
||||||
|
throws Exception {
|
||||||
|
PropertySource<?> source = new MapPropertySource("foo",
|
||||||
|
Collections.<String, Object>singletonMap("foo", "bar"));
|
||||||
|
ConfigurationPropertySource configurationPropertySource = ConfigurationPropertySources
|
||||||
|
.from(source).iterator().next();
|
||||||
|
assertThat(configurationPropertySource)
|
||||||
|
.isInstanceOf(SpringConfigurationPropertySource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromPropertySourcseShouldFlattenPropertySources() throws Exception {
|
||||||
StandardEnvironment environment = new StandardEnvironment();
|
StandardEnvironment environment = new StandardEnvironment();
|
||||||
environment.getPropertySources().addFirst(new MapPropertySource("foo",
|
environment.getPropertySources().addFirst(new MapPropertySource("foo",
|
||||||
Collections.<String, Object>singletonMap("foo", "bar")));
|
Collections.<String, Object>singletonMap("foo", "bar")));
|
||||||
|
|
@ -231,27 +119,9 @@ public class ConfigurationPropertySourcesTests {
|
||||||
});
|
});
|
||||||
sources.addLast(new MapPropertySource("baz",
|
sources.addLast(new MapPropertySource("baz",
|
||||||
Collections.<String, Object>singletonMap("baz", "barf")));
|
Collections.<String, Object>singletonMap("baz", "barf")));
|
||||||
ConfigurationPropertySources configurationSources = ConfigurationPropertySources
|
Iterable<ConfigurationPropertySource> configurationSources = ConfigurationPropertySources
|
||||||
.get(sources);
|
.from(sources);
|
||||||
assertThat(configurationSources.iterator()).hasSize(5);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
public class DefaultPropertyMapperTests extends AbstractPropertyMapperTests {
|
public class DefaultPropertyMapperTests extends AbstractPropertyMapperTests {
|
||||||
|
|
||||||
private DefaultPropertyMapper mapper = new DefaultPropertyMapper();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyMapper getMapper() {
|
protected PropertyMapper getMapper() {
|
||||||
return this.mapper;
|
return DefaultPropertyMapper.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link PropertySourceConfigurationPropertySource}.
|
* Tests for {@link SpringConfigurationPropertySource}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
*/
|
*/
|
||||||
public class PropertySourceConfigurationPropertySourceTests {
|
public class SpringConfigurationPropertySourceTests {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
@ -46,16 +46,14 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
public void createWhenPropertySourceIsNullShouldThrowException() throws Exception {
|
public void createWhenPropertySourceIsNullShouldThrowException() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("PropertySource must not be null");
|
this.thrown.expectMessage("PropertySource must not be null");
|
||||||
new PropertySourceConfigurationPropertySource(null, mock(PropertyMapper.class),
|
new SpringConfigurationPropertySource(null, mock(PropertyMapper.class), null);
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createWhenMapperIsNullShouldThrowException() throws Exception {
|
public void createWhenMapperIsNullShouldThrowException() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("Mapper must not be null");
|
this.thrown.expectMessage("Mapper must not be null");
|
||||||
new PropertySourceConfigurationPropertySource(mock(PropertySource.class), null,
|
new SpringConfigurationPropertySource(mock(PropertySource.class), null, null);
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -68,7 +66,7 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key2");
|
mapper.addFromConfigurationProperty(name, "key2");
|
||||||
PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource(
|
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||||
propertySource, mapper, null);
|
propertySource, mapper, null);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +80,7 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key",
|
mapper.addFromConfigurationProperty(name, "key",
|
||||||
(value) -> value.toString().replace("ue", "let"));
|
(value) -> value.toString().replace("ue", "let"));
|
||||||
PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource(
|
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||||
propertySource, mapper, null);
|
propertySource, mapper, null);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +93,7 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key");
|
mapper.addFromConfigurationProperty(name, "key");
|
||||||
PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource(
|
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||||
propertySource, mapper, null);
|
propertySource, mapper, null);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
||||||
.isEqualTo("\"key\" from property source \"test\"");
|
.isEqualTo("\"key\" from property source \"test\"");
|
||||||
|
|
@ -110,7 +108,7 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key");
|
mapper.addFromConfigurationProperty(name, "key");
|
||||||
PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource(
|
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||||
propertySource, mapper, null);
|
propertySource, mapper, null);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
||||||
.isEqualTo("TestOrigin key");
|
.isEqualTo("TestOrigin key");
|
||||||
|
|
@ -121,12 +119,61 @@ public class PropertySourceConfigurationPropertySourceTests {
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
source.put("foo.bar", "value");
|
source.put("foo.bar", "value");
|
||||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||||
PropertySourceConfigurationPropertySource adapter = new PropertySourceConfigurationPropertySource(
|
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||||
propertySource, new DefaultPropertyMapper(), null);
|
propertySource, DefaultPropertyMapper.INSTANCE, null);
|
||||||
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo")))
|
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo")))
|
||||||
.isEmpty();
|
.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<Object>("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<String, Object> source = new LinkedHashMap<String, Object>() {
|
||||||
|
|
||||||
|
@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<String, Object> 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}.
|
* Test {@link PropertySource} that's also a {@link OriginLookup}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -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.<String, Object>singletonMap("a", "b")));
|
||||||
|
Iterator<ConfigurationPropertySource> 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.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
||||||
|
Iterator<ConfigurationPropertySource> 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.<String, Object>singletonMap("SERVER_PORT", "1234")));
|
||||||
|
sources.addLast(new MapPropertySource("test1",
|
||||||
|
Collections.<String, Object>singletonMap("server.po-rt", "4567")));
|
||||||
|
sources.addLast(new MapPropertySource("test2",
|
||||||
|
Collections.<String, Object>singletonMap("a", "b")));
|
||||||
|
Iterator<ConfigurationPropertySource> 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.<String, Object>singletonMap("foo", "bar")));
|
||||||
|
environment.getPropertySources().addFirst(new MapPropertySource("far",
|
||||||
|
Collections.<String, Object>singletonMap("far", "far")));
|
||||||
|
MutablePropertySources sources = new MutablePropertySources();
|
||||||
|
sources.addFirst(new PropertySource<Environment>("env", environment) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String key) {
|
||||||
|
return this.source.getProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
sources.addLast(new MapPropertySource("baz",
|
||||||
|
Collections.<String, Object>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.<String, Object>singletonMap("a", "b")));
|
||||||
|
assertThat(new SpringConfigurationPropertySources(sources).iterator()).hasSize(1);
|
||||||
|
sources.addLast(new MapPropertySource("test2",
|
||||||
|
Collections.<String, Object>singletonMap("b", "c")));
|
||||||
|
assertThat(new SpringConfigurationPropertySources(sources).iterator()).hasSize(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -33,12 +33,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link PropertySourceIterableConfigurationPropertySource}.
|
* Tests for {@link SpringIterableConfigurationPropertySource}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
*/
|
*/
|
||||||
public class PropertySourceIterableConfigurationPropertySourceTests {
|
public class SpringIterableConfigurationPropertySourceTests {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
@ -47,15 +47,14 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
public void createWhenPropertySourceIsNullShouldThrowException() throws Exception {
|
public void createWhenPropertySourceIsNullShouldThrowException() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("PropertySource must not be null");
|
this.thrown.expectMessage("PropertySource must not be null");
|
||||||
new PropertySourceIterableConfigurationPropertySource(null,
|
new SpringIterableConfigurationPropertySource(null, mock(PropertyMapper.class));
|
||||||
mock(PropertyMapper.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createWhenMapperIsNullShouldThrowException() throws Exception {
|
public void createWhenMapperIsNullShouldThrowException() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("Mapper must not be null");
|
this.thrown.expectMessage("Mapper must not be null");
|
||||||
new PropertySourceIterableConfigurationPropertySource(
|
new SpringIterableConfigurationPropertySource(
|
||||||
mock(EnumerablePropertySource.class), null);
|
mock(EnumerablePropertySource.class), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +71,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
mapper.addFromPropertySource("key1", "my.key1");
|
mapper.addFromPropertySource("key1", "my.key1");
|
||||||
mapper.addFromPropertySource("key2", "my.key2a", "my.key2b");
|
mapper.addFromPropertySource("key2", "my.key2a", "my.key2b");
|
||||||
mapper.addFromPropertySource("key4", "my.key4");
|
mapper.addFromPropertySource("key4", "my.key4");
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
assertThat(adapter.iterator()).extracting(Object::toString)
|
assertThat(adapter.iterator()).extracting(Object::toString)
|
||||||
.containsExactly("my.key1", "my.key2a", "my.key2b", "my.key4");
|
.containsExactly("my.key1", "my.key2a", "my.key2b", "my.key4");
|
||||||
|
|
@ -89,7 +88,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key2");
|
mapper.addFromConfigurationProperty(name, "key2");
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +104,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
mapper.addFromPropertySource("key1", "my.missing");
|
mapper.addFromPropertySource("key1", "my.missing");
|
||||||
mapper.addFromPropertySource("key2", "my.k-e-y");
|
mapper.addFromPropertySource("key2", "my.k-e-y");
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
||||||
|
|
@ -121,7 +120,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key",
|
mapper.addFromConfigurationProperty(name, "key",
|
||||||
(value) -> value.toString().replace("ue", "let"));
|
(value) -> value.toString().replace("ue", "let"));
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +134,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key");
|
mapper.addFromConfigurationProperty(name, "key");
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
||||||
.isEqualTo("\"key\" from property source \"test\"");
|
.isEqualTo("\"key\" from property source \"test\"");
|
||||||
|
|
@ -150,7 +149,7 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||||
mapper.addFromConfigurationProperty(name, "key");
|
mapper.addFromConfigurationProperty(name, "key");
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, mapper);
|
propertySource, mapper);
|
||||||
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
assertThat(adapter.getConfigurationProperty(name).getOrigin().toString())
|
||||||
.isEqualTo("TestOrigin key");
|
.isEqualTo("TestOrigin key");
|
||||||
|
|
@ -163,8 +162,8 @@ public class PropertySourceIterableConfigurationPropertySourceTests {
|
||||||
source.put("faf", "value");
|
source.put("faf", "value");
|
||||||
EnumerablePropertySource<?> propertySource = new OriginCapablePropertySource<>(
|
EnumerablePropertySource<?> propertySource = new OriginCapablePropertySource<>(
|
||||||
new MapPropertySource("test", source));
|
new MapPropertySource("test", source));
|
||||||
PropertySourceIterableConfigurationPropertySource adapter = new PropertySourceIterableConfigurationPropertySource(
|
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||||
propertySource, new DefaultPropertyMapper());
|
propertySource, DefaultPropertyMapper.INSTANCE);
|
||||||
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo")))
|
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("foo")))
|
||||||
.contains(true);
|
.contains(true);
|
||||||
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("faf")))
|
assertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of("faf")))
|
||||||
|
|
@ -36,11 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapperTests {
|
public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapperTests {
|
||||||
|
|
||||||
private SystemEnvironmentPropertyMapper mapper = new SystemEnvironmentPropertyMapper();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyMapper getMapper() {
|
protected PropertyMapper getMapper() {
|
||||||
return this.mapper;
|
return SystemEnvironmentPropertyMapper.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -75,7 +73,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
source.put("SERVER__", "foo,bar,baz");
|
source.put("SERVER__", "foo,bar,baz");
|
||||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||||
List<PropertyMapping> mappings = this.mapper.map(propertySource, "SERVER__");
|
List<PropertyMapping> mappings = getMapper().map(propertySource, "SERVER__");
|
||||||
List<Object> result = new ArrayList<>();
|
List<Object> result = new ArrayList<>();
|
||||||
for (PropertyMapping mapping : mappings) {
|
for (PropertyMapping mapping : mappings) {
|
||||||
Object value = propertySource.getProperty(mapping.getPropertySourceName());
|
Object value = propertySource.getProperty(mapping.getPropertySourceName());
|
||||||
|
|
@ -91,7 +89,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
source.put("SERVER__", "foo,bar,baz");
|
source.put("SERVER__", "foo,bar,baz");
|
||||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||||
List<PropertyMapping> mappings = this.mapper.map(propertySource,
|
List<PropertyMapping> mappings = getMapper().map(propertySource,
|
||||||
ConfigurationPropertyName.of("server[1]"));
|
ConfigurationPropertyName.of("server[1]"));
|
||||||
List<Object> result = new ArrayList<>();
|
List<Object> result = new ArrayList<>();
|
||||||
for (PropertyMapping mapping : mappings) {
|
for (PropertyMapping mapping : mappings) {
|
||||||
|
|
@ -108,7 +106,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||||
public void underscoreShouldNotMapToEmptyString() throws Exception {
|
public void underscoreShouldNotMapToEmptyString() throws Exception {
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||||
List<PropertyMapping> mappings = this.mapper.map(propertySource, "_");
|
List<PropertyMapping> mappings = getMapper().map(propertySource, "_");
|
||||||
boolean applicable = false;
|
boolean applicable = false;
|
||||||
for (PropertyMapping mapping : mappings) {
|
for (PropertyMapping mapping : mappings) {
|
||||||
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
||||||
|
|
@ -120,7 +118,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||||
public void underscoreWithWhitespaceShouldNotMapToEmptyString() throws Exception {
|
public void underscoreWithWhitespaceShouldNotMapToEmptyString() throws Exception {
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||||
List<PropertyMapping> mappings = this.mapper.map(propertySource, " _");
|
List<PropertyMapping> mappings = getMapper().map(propertySource, " _");
|
||||||
boolean applicable = false;
|
boolean applicable = false;
|
||||||
for (PropertyMapping mapping : mappings) {
|
for (PropertyMapping mapping : mappings) {
|
||||||
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue