Browse Source

Restore binding of system environment using legacy names

Remove `Binder` optimization introduced in commit 8f14dca164 so that
legacy format names in environment variables can be used again.

Fixes gh-46184
pull/46457/head
Phillip Webb 10 months ago
parent
commit
6fe696b5cf
  1. 13
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/IndexedElementsBinder.java
  2. 37
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java

13
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/IndexedElementsBinder.java

@ -107,7 +107,6 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> { @@ -107,7 +107,6 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> {
AggregateElementBinder elementBinder, IndexedCollectionSupplier collection, ResolvableType elementType) {
Set<String> knownIndexedChildren = Collections.emptySet();
if (source instanceof IterableConfigurationPropertySource iterableSource) {
source = iterableSource.filter(root::isAncestorOf);
knownIndexedChildren = getKnownIndexedChildren(iterableSource, root);
}
for (int i = 0; i < Integer.MAX_VALUE; i++) {
@ -124,10 +123,10 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> { @@ -124,10 +123,10 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> {
}
}
private Set<String> getKnownIndexedChildren(IterableConfigurationPropertySource filteredSource,
private Set<String> getKnownIndexedChildren(IterableConfigurationPropertySource source,
ConfigurationPropertyName root) {
Set<String> knownIndexedChildren = new HashSet<>();
for (ConfigurationPropertyName name : filteredSource) {
for (ConfigurationPropertyName name : source.filter(root::isAncestorOf)) {
ConfigurationPropertyName choppedName = name.chop(root.getNumberOfElements() + 1);
if (choppedName.isLastElementIndexed()) {
knownIndexedChildren.add(choppedName.getLastElement(Form.UNIFORM));
@ -136,17 +135,17 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> { @@ -136,17 +135,17 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> {
return knownIndexedChildren;
}
private void assertNoUnboundChildren(Set<String> unboundIndexedChildren,
IterableConfigurationPropertySource filteredSource, ConfigurationPropertyName root) {
private void assertNoUnboundChildren(Set<String> unboundIndexedChildren, IterableConfigurationPropertySource source,
ConfigurationPropertyName root) {
if (unboundIndexedChildren.isEmpty()) {
return;
}
Set<ConfigurationProperty> unboundProperties = new TreeSet<>();
for (ConfigurationPropertyName name : filteredSource) {
for (ConfigurationPropertyName name : source.filter(root::isAncestorOf)) {
ConfigurationPropertyName choppedName = name.chop(root.getNumberOfElements() + 1);
if (choppedName.isLastElementIndexed()
&& unboundIndexedChildren.contains(choppedName.getLastElement(Form.UNIFORM))) {
unboundProperties.add(filteredSource.getConfigurationProperty(name));
unboundProperties.add(source.getConfigurationProperty(name));
}
}
if (!unboundProperties.isEmpty()) {

37
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java

@ -19,9 +19,11 @@ package org.springframework.boot.context.properties.bind; @@ -19,9 +19,11 @@ package org.springframework.boot.context.properties.bind;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
@ -33,6 +35,7 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS @@ -33,6 +35,7 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS
import org.springframework.boot.context.properties.source.MockConfigurationPropertySource;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.SystemEnvironmentPropertySource;
import org.springframework.test.context.support.TestPropertySourceUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -465,6 +468,36 @@ class CollectionBinderTests { @@ -465,6 +468,36 @@ class CollectionBinderTests {
assertThat(result.getValues().get(0)).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);
}
@Test
void bindToWellFormedSystemEnvironmentVariableProperty() {
// gh-46184
Map<String, Object> map = new LinkedHashMap<>();
map.put("FOO_THENAMES_0_FIRST", "spring");
map.put("FOO_THENAMES_0_LAST", "boot");
map.put("FOO_THENAMES_1_FIRST", "binding");
map.put("FOO_THENAMES_1_LAST", "test");
SystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map);
this.sources.add(ConfigurationPropertySource.from(propertySource));
BeanWithCamelCaseNameList result = this.binder.bind("foo", BeanWithCamelCaseNameList.class).get();
assertThat(result.theNames()).containsExactly(new Name("spring", "boot"), new Name("binding", "test"));
}
@Test
void bindToLegacySystemEnvironmentVariableProperty() {
// gh-46184
Map<String, Object> map = new LinkedHashMap<>();
map.put("FOO_THE_NAMES_0_FIRST", "spring");
map.put("FOO_THE_NAMES_0_LAST", "boot");
map.put("FOO_THE_NAMES_1_FIRST", "binding");
map.put("FOO_THE_NAMES_1_LAST", "test");
SystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map);
this.sources.add(ConfigurationPropertySource.from(propertySource));
BeanWithCamelCaseNameList result = this.binder.bind("foo", BeanWithCamelCaseNameList.class).get();
assertThat(result.theNames()).containsExactly(new Name("spring", "boot"), new Name("binding", "test"));
}
static class ExampleCollectionBean {
private final List<String> items = new ArrayList<>();
@ -607,6 +640,10 @@ class CollectionBinderTests { @@ -607,6 +640,10 @@ class CollectionBinderTests {
}
record BeanWithCamelCaseNameList(List<Name> theNames) {
}
record Name(String first, String last) {
}

Loading…
Cancel
Save