Drop environment variable "__" list support
Remove support for the `__` environment variable list shortcut in order to reduce complexity. The shortcut was developed before the new `Binder` code was fully formed and isn't really necessary now since comma-lists can be converted automatically. Fixes gh-11410
This commit is contained in:
@@ -19,7 +19,6 @@ package org.springframework.boot.context.properties.source;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -44,7 +43,7 @@ final class DefaultPropertyMapper implements PropertyMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
public List<PropertyMapping> map(
|
||||
ConfigurationPropertyName configurationPropertyName) {
|
||||
// Use a local copy in case another thread changes things
|
||||
LastMapping<ConfigurationPropertyName> last = this.lastMappedConfigurationPropertyName;
|
||||
@@ -60,8 +59,7 @@ final class DefaultPropertyMapper implements PropertyMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
String propertySourceName) {
|
||||
public List<PropertyMapping> map(String propertySourceName) {
|
||||
// Use a local copy in case another thread changes things
|
||||
LastMapping<String> last = this.lastMappedPropertyName;
|
||||
if (last != null && last.isFrom(propertySourceName)) {
|
||||
|
||||
@@ -43,20 +43,16 @@ interface PropertyMapper {
|
||||
/**
|
||||
* Provide mappings from a {@link ConfigurationPropertySource}
|
||||
* {@link ConfigurationPropertyName}.
|
||||
* @param propertySource the property source
|
||||
* @param configurationPropertyName the name to map
|
||||
* @return a stream of mappings or {@code Stream#empty()}
|
||||
*/
|
||||
List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
ConfigurationPropertyName configurationPropertyName);
|
||||
List<PropertyMapping> map(ConfigurationPropertyName configurationPropertyName);
|
||||
|
||||
/**
|
||||
* Provide mappings from a {@link PropertySource} property name.
|
||||
* @param propertySource the property source
|
||||
* @param propertySourceName the name to map
|
||||
* @return a stream of mappings or {@code Stream#empty()}
|
||||
*/
|
||||
List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
String propertySourceName);
|
||||
List<PropertyMapping> map(String propertySourceName);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.context.properties.source;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
@@ -34,8 +32,6 @@ class PropertyMapping {
|
||||
|
||||
private final ConfigurationPropertyName configurationPropertyName;
|
||||
|
||||
private final Function<Object, Object> valueExtractor;
|
||||
|
||||
/**
|
||||
* Create a new {@link PropertyMapper} instance.
|
||||
* @param propertySourceName the {@link PropertySource} name
|
||||
@@ -44,22 +40,8 @@ class PropertyMapping {
|
||||
*/
|
||||
PropertyMapping(String propertySourceName,
|
||||
ConfigurationPropertyName configurationPropertyName) {
|
||||
this(propertySourceName, configurationPropertyName, Function.identity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PropertyMapper} instance.
|
||||
* @param propertySourceName the {@link PropertySource} name
|
||||
* @param configurationPropertyName the {@link ConfigurationPropertySource}
|
||||
* {@link ConfigurationPropertyName}
|
||||
* @param valueExtractor the extractor used to obtain the value
|
||||
*/
|
||||
PropertyMapping(String propertySourceName,
|
||||
ConfigurationPropertyName configurationPropertyName,
|
||||
Function<Object, Object> valueExtractor) {
|
||||
this.propertySourceName = propertySourceName;
|
||||
this.configurationPropertyName = configurationPropertyName;
|
||||
this.valueExtractor = valueExtractor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,14 +63,6 @@ class PropertyMapping {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a function that can be used to extract the {@link PropertySource} value.
|
||||
* @return the value extractor (never {@code null})
|
||||
*/
|
||||
public Function<Object, Object> getValueExtractor() {
|
||||
return this.valueExtractor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this mapping is applicable for the given
|
||||
* {@link ConfigurationPropertyName}.
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.springframework.util.Assert;
|
||||
* <p>
|
||||
* Each {@link ConfigurationPropertySource#getConfigurationProperty
|
||||
* getConfigurationProperty} call attempts to
|
||||
* {@link PropertyMapper#map(PropertySource, ConfigurationPropertyName) map} the
|
||||
* {@link PropertyMapper#map(ConfigurationPropertyName) map} the
|
||||
* {@link ConfigurationPropertyName} to one or more {@code String} based names. This
|
||||
* allows fast property resolution for well formed property sources.
|
||||
* <p>
|
||||
@@ -85,7 +85,7 @@ class SpringConfigurationPropertySource implements ConfigurationPropertySource {
|
||||
@Override
|
||||
public ConfigurationProperty getConfigurationProperty(
|
||||
ConfigurationPropertyName name) {
|
||||
List<PropertyMapping> mappings = getMapper().map(getPropertySource(), name);
|
||||
List<PropertyMapping> mappings = getMapper().map(name);
|
||||
return find(mappings, name);
|
||||
}
|
||||
|
||||
@@ -112,7 +112,6 @@ class SpringConfigurationPropertySource implements ConfigurationPropertySource {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
value = mapping.getValueExtractor().apply(value);
|
||||
ConfigurationPropertyName configurationPropertyName = mapping
|
||||
.getConfigurationPropertyName();
|
||||
Origin origin = PropertySourceOrigin.get(this.propertySource, propertySourceName);
|
||||
@@ -215,10 +214,10 @@ class SpringConfigurationPropertySource implements ConfigurationPropertySource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
public List<PropertyMapping> map(
|
||||
ConfigurationPropertyName configurationPropertyName) {
|
||||
try {
|
||||
return this.mapper.map(propertySource, configurationPropertyName);
|
||||
return this.mapper.map(configurationPropertyName);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return Collections.emptyList();
|
||||
@@ -226,10 +225,9 @@ class SpringConfigurationPropertySource implements ConfigurationPropertySource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
String propertySourceName) {
|
||||
public List<PropertyMapping> map(String propertySourceName) {
|
||||
try {
|
||||
return this.mapper.map(propertySource, propertySourceName);
|
||||
return this.mapper.map(propertySourceName);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -119,7 +119,7 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
|
||||
String[] names = getPropertySource().getPropertyNames();
|
||||
mappings = new ArrayList<>(names.length);
|
||||
for (String name : names) {
|
||||
mappings.addAll(getMapper().map(getPropertySource(), name));
|
||||
mappings.addAll(getMapper().map(name));
|
||||
}
|
||||
mappings = Collections.unmodifiableList(mappings);
|
||||
if (cache != null) {
|
||||
|
||||
@@ -21,12 +21,9 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PropertyMapper} for system environment variables. Names are mapped by removing
|
||||
@@ -52,7 +49,7 @@ final class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
public List<PropertyMapping> map(
|
||||
ConfigurationPropertyName configurationPropertyName) {
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
names.add(convertName(configurationPropertyName));
|
||||
@@ -60,39 +57,15 @@ final class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
||||
List<PropertyMapping> result = new ArrayList<>();
|
||||
names.forEach((name) -> result
|
||||
.add(new PropertyMapping(name, configurationPropertyName)));
|
||||
if (isListShortcutPossible(configurationPropertyName)) {
|
||||
result.addAll(mapListShortcut(propertySource, configurationPropertyName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isListShortcutPossible(ConfigurationPropertyName name) {
|
||||
return (name.isLastElementIndexed() && isNumber(name.getLastElement(Form.UNIFORM))
|
||||
&& name.getNumberOfElements() >= 1);
|
||||
}
|
||||
|
||||
private List<PropertyMapping> mapListShortcut(PropertySource<?> propertySource,
|
||||
ConfigurationPropertyName name) {
|
||||
String result = convertName(name, name.getNumberOfElements() - 1) + "__";
|
||||
if (propertySource.containsProperty(result)) {
|
||||
int index = Integer.parseInt(name.getLastElement(Form.UNIFORM));
|
||||
return Collections.singletonList(
|
||||
new PropertyMapping(result, name, new ElementExtractor(index)));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
String propertySourceName) {
|
||||
public List<PropertyMapping> map(String propertySourceName) {
|
||||
ConfigurationPropertyName name = convertName(propertySourceName);
|
||||
if (name == null || name.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (propertySourceName.endsWith("__")) {
|
||||
return expandListShortcut(propertySourceName, name,
|
||||
propertySource.getProperty(propertySourceName));
|
||||
}
|
||||
return Collections.singletonList(new PropertyMapping(propertySourceName, name));
|
||||
}
|
||||
|
||||
@@ -106,22 +79,6 @@ final class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
||||
}
|
||||
}
|
||||
|
||||
private List<PropertyMapping> expandListShortcut(String propertySourceName,
|
||||
ConfigurationPropertyName rootName, Object value) {
|
||||
if (value == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PropertyMapping> mappings = new ArrayList<>();
|
||||
String[] elements = StringUtils
|
||||
.commaDelimitedListToStringArray(String.valueOf(value));
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
ConfigurationPropertyName name = rootName.append("[" + i + "]");
|
||||
mappings.add(new PropertyMapping(propertySourceName, name,
|
||||
new ElementExtractor(i)));
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
private String convertName(ConfigurationPropertyName name) {
|
||||
return convertName(name, name.getNumberOfElements());
|
||||
}
|
||||
@@ -159,26 +116,4 @@ final class SystemEnvironmentPropertyMapper implements PropertyMapper {
|
||||
return !hasNonDigit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to extract an element from a comma list.
|
||||
*/
|
||||
private static class ElementExtractor implements Function<Object, Object> {
|
||||
|
||||
private final int index;
|
||||
|
||||
ElementExtractor(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return StringUtils
|
||||
.commaDelimitedListToStringArray(value.toString())[this.index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,8 @@
|
||||
|
||||
package org.springframework.boot.context.properties.source;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link PropertyMapper} tests.
|
||||
*
|
||||
@@ -38,9 +34,7 @@ public abstract class AbstractPropertyMapperTests {
|
||||
}
|
||||
|
||||
protected final Iterator<String> namesFromString(String name, Object value) {
|
||||
PropertySource<?> propertySource = new MapPropertySource("test",
|
||||
Collections.singletonMap(name, value));
|
||||
return getMapper().map(propertySource, name).stream()
|
||||
return getMapper().map(name).stream()
|
||||
.map((mapping) -> mapping.getConfigurationPropertyName().toString())
|
||||
.iterator();
|
||||
}
|
||||
@@ -50,10 +44,8 @@ public abstract class AbstractPropertyMapperTests {
|
||||
}
|
||||
|
||||
protected final Iterator<String> namesFromConfiguration(String name, String value) {
|
||||
PropertySource<?> propertySource = new MapPropertySource("test",
|
||||
Collections.singletonMap(name, value));
|
||||
return getMapper().map(propertySource, ConfigurationPropertyName.of(name))
|
||||
.stream().map(PropertyMapping::getPropertySourceName).iterator();
|
||||
return getMapper().map(ConfigurationPropertyName.of(name)).stream()
|
||||
.map(PropertyMapping::getPropertySourceName).iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,20 +71,6 @@ public class SpringConfigurationPropertySourceTests {
|
||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValueShouldUseExtractor() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("key", "value");
|
||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||
mapper.addFromConfigurationProperty(name, "key",
|
||||
(value) -> value.toString().replace("ue", "let"));
|
||||
SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(
|
||||
propertySource, mapper, null);
|
||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValueOrigin() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
|
||||
@@ -110,21 +110,6 @@ public class SpringIterableConfigurationPropertySourceTests {
|
||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValueShouldUseExtractor() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("key", "value");
|
||||
EnumerablePropertySource<?> propertySource = new MapPropertySource("test",
|
||||
source);
|
||||
TestPropertyMapper mapper = new TestPropertyMapper();
|
||||
ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key");
|
||||
mapper.addFromConfigurationProperty(name, "key",
|
||||
(value) -> value.toString().replace("ue", "let"));
|
||||
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
|
||||
propertySource, mapper);
|
||||
assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("vallet");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValueOrigin() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
|
||||
@@ -16,16 +16,10 @@
|
||||
|
||||
package org.springframework.boot.context.properties.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -50,10 +44,6 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||
assertThat(namesFromString("HOST_0_NAME")).containsExactly("host[0].name");
|
||||
assertThat(namesFromString("HOST_F00_NAME")).containsExactly("host.f00.name");
|
||||
assertThat(namesFromString("S-ERVER")).containsExactly("s-erver");
|
||||
assertThat(namesFromString("SERVERS__", "1,2,3")).containsExactly("servers[0]",
|
||||
"servers[1]", "servers[2]");
|
||||
assertThat(namesFromString("SERVERS_0__", "1,2,3"))
|
||||
.containsExactly("servers[0][0]", "servers[0][1]", "servers[0][2]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -69,44 +59,9 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||
"FOO_THE_BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapFromStringWhenListShortcutShouldExtractValues() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("SERVER__", "foo,bar,baz");
|
||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||
List<PropertyMapping> mappings = getMapper().map(propertySource, "SERVER__");
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (PropertyMapping mapping : mappings) {
|
||||
Object value = propertySource.getProperty(mapping.getPropertySourceName());
|
||||
value = mapping.getValueExtractor().apply(value);
|
||||
result.add(value);
|
||||
}
|
||||
assertThat(result).containsExactly("foo", "bar", "baz");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapFromConfigurationShouldIncludeShortcutAndExtractValues() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
source.put("SERVER__", "foo,bar,baz");
|
||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||
List<PropertyMapping> mappings = getMapper().map(propertySource,
|
||||
ConfigurationPropertyName.of("server[1]"));
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (PropertyMapping mapping : mappings) {
|
||||
Object value = propertySource.getProperty(mapping.getPropertySourceName());
|
||||
value = mapping.getValueExtractor().apply(value);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
assertThat(result).containsExactly("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underscoreShouldNotMapToEmptyString() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||
List<PropertyMapping> mappings = getMapper().map(propertySource, "_");
|
||||
List<PropertyMapping> mappings = getMapper().map("_");
|
||||
boolean applicable = false;
|
||||
for (PropertyMapping mapping : mappings) {
|
||||
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
||||
@@ -116,9 +71,7 @@ public class SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapper
|
||||
|
||||
@Test
|
||||
public void underscoreWithWhitespaceShouldNotMapToEmptyString() {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
PropertySource<?> propertySource = new MapPropertySource("test", source);
|
||||
List<PropertyMapping> mappings = getMapper().map(propertySource, " _");
|
||||
List<PropertyMapping> mappings = getMapper().map(" _");
|
||||
boolean applicable = false;
|
||||
for (PropertyMapping mapping : mappings) {
|
||||
applicable = mapping.isApplicable(ConfigurationPropertyName.of(""));
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -53,13 +52,12 @@ class TestPropertyMapper implements PropertyMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
String propertySourceName) {
|
||||
public List<PropertyMapping> map(String propertySourceName) {
|
||||
return this.fromSource.getOrDefault(propertySourceName, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyMapping> map(PropertySource<?> propertySource,
|
||||
public List<PropertyMapping> map(
|
||||
ConfigurationPropertyName configurationPropertyName) {
|
||||
return this.fromConfig.getOrDefault(configurationPropertyName,
|
||||
Collections.emptyList());
|
||||
|
||||
Reference in New Issue
Block a user