Bind empty strings to empty maps

Align `MapBinder` with `IndexedElementsBinder` to ensure that
empty strings are bound as empty `Map` instances rather than
throwing a `ConverterNotFoundException`.

See gh-50773

Signed-off-by: Ahmed El amraouiyine <ahmed.elamraouiyine@vilavi.fr>
This commit is contained in:
Ahmed El amraouiyine
2026-06-20 19:44:29 -07:00
committed by Phillip Webb
parent f71e797761
commit 485bd7c636
2 changed files with 24 additions and 0 deletions
@@ -33,6 +33,7 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS
import org.springframework.boot.context.properties.source.IterableConfigurationPropertySource;
import org.springframework.core.CollectionFactory;
import org.springframework.core.ResolvableType;
import org.springframework.util.ObjectUtils;
/**
* {@link AggregateBinder} for Maps.
@@ -64,6 +65,9 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
if (property != null) {
getContext().setConfigurationProperty(property);
Object result = getContext().getPlaceholdersResolver().resolvePlaceholders(property.getValue());
if (ObjectUtils.isEmpty(result)) {
return createMap(target);
}
return getContext().getConverter().convert(result, target);
}
}
@@ -274,6 +274,15 @@ class MapBinderTests {
assertThat(result.isBound()).isFalse();
}
@Test
void bindToMapWhenEmptyStringShouldReturnEmptyMap() {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo", "");
this.sources.add(source);
Map<String, String> result = this.binder.bind("foo", STRING_STRING_MAP).get();
assertThat(result).isEmpty();
}
@Test
void bindToMapShouldConvertKey() {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
@@ -510,6 +519,17 @@ class MapBinderTests {
assertThat(foo2.getValue()).isEqualTo("three");
}
@Test
void nestedMapsWhenEmptyStringShouldReturnEmptyMap() {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo.value", "one");
source.put("foo.foos", "");
this.sources.add(source);
BindResult<NestableFoo> foo = this.binder.bind("foo", NestableFoo.class);
assertThat(foo.get().getValue()).isEqualTo("one");
assertThat(foo.get().getFoos()).isEmpty();
}
@Test
void bindToMapWithCustomConverter() {
DefaultConversionService conversionService = new DefaultConversionService();