Skip to content

Commit 3992dac

Browse files
committed
Bind empty string to empty collection or array of rich types
Previously, when an empty String was bound to a collection or array of rich types it would fail as there was no converter capable of creating a Collection<RichType> or RichType[] from the String. This commit updates IndexedElementsBinder to apply special treatment to empty String values. Now, when such a value is being processed, an empty Collection or array is the result. Closes gh-12965
1 parent 45f4e87 commit 3992dac

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Annotation;
2020
import java.util.Collection;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.TreeSet;
2324
import java.util.function.Supplier;
@@ -32,6 +33,7 @@
3233
import org.springframework.core.ResolvableType;
3334
import org.springframework.util.LinkedMultiValueMap;
3435
import org.springframework.util.MultiValueMap;
36+
import org.springframework.util.StringUtils;
3537

3638
/**
3739
* Base class for {@link AggregateBinder AggregateBinders} that read a sequential run of
@@ -81,11 +83,17 @@ private void bindIndexed(ConfigurationPropertySource source,
8183
ResolvableType aggregateType, ResolvableType elementType) {
8284
ConfigurationProperty property = source.getConfigurationProperty(root);
8385
if (property != null) {
84-
Object aggregate = convert(property.getValue(), aggregateType,
85-
target.getAnnotations());
86-
ResolvableType collectionType = ResolvableType
87-
.forClassWithGenerics(collection.get().getClass(), elementType);
88-
Collection<Object> elements = convert(aggregate, collectionType);
86+
Collection<Object> elements;
87+
Object value = property.getValue();
88+
if (value instanceof String && !StringUtils.hasText((String) value)) {
89+
elements = Collections.emptyList();
90+
}
91+
else {
92+
Object aggregate = convert(value, aggregateType, target.getAnnotations());
93+
ResolvableType collectionType = ResolvableType
94+
.forClassWithGenerics(collection.get().getClass(), elementType);
95+
elements = convert(aggregate, collectionType);
96+
}
8997
collection.get().addAll(elements);
9098
}
9199
else {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,19 @@ public void bindToBeanWithNestedCollectionShouldPopulateCollection() {
363363
assertThat(foo.getFoos().get(1).getValue()).isEqualTo("three");
364364
}
365365

366+
@Test
367+
public void bindToNestedCollectionWhenEmptyStringShouldReturnEmptyCollection() {
368+
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
369+
source.put("foo.value", "one");
370+
source.put("foo.foos", "");
371+
this.sources.add(source);
372+
Bindable<BeanWithNestedCollection> target = Bindable
373+
.of(BeanWithNestedCollection.class);
374+
BeanWithNestedCollection foo = this.binder.bind("foo", target).get();
375+
assertThat(foo.getValue()).isEqualTo("one");
376+
assertThat(foo.getFoos()).isEmpty();
377+
}
378+
366379
@Test
367380
public void bindToCollectionShouldUsePropertyEditor() {
368381
// gh-12166

0 commit comments

Comments
 (0)