Try to convert value in MapBinder

Fixes gh-11493
pull/11498/merge
Madhura Bhave 7 years ago
parent 47acf8acdc
commit 41c02b307b

@ -27,6 +27,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.core.convert.ConverterNotFoundException;
import org.springframework.util.ClassUtils;
/**
@ -57,6 +58,10 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
Bindable<?> resolvedTarget = resolveTarget(target);
for (ConfigurationPropertySource source : getContext().getSources()) {
if (!ConfigurationPropertyName.EMPTY.equals(name)) {
Object converted = convertIfFound(name, source, resolvedTarget);
if (converted != null) {
return converted;
}
source = source.filter(name::isAncestorOf);
}
new EntryBinder(name, resolvedTarget, elementBinder).bindEntries(source, map);
@ -72,6 +77,20 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
return target;
}
private Object convertIfFound(ConfigurationPropertyName name, ConfigurationPropertySource source, Bindable<?> target) {
ConfigurationProperty configurationProperty = source.getConfigurationProperty(name);
if (configurationProperty != null) {
try {
return ResolvableTypeDescriptor.forType(target.getType())
.convert(getContext().getConversionService(), configurationProperty.getValue());
}
catch (ConverterNotFoundException ex) {
}
}
return null;
}
@Override
protected Map<Object, Object> merge(Map<Object, Object> existing,
Map<Object, Object> additional) {

@ -38,8 +38,11 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyS
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MockConfigurationPropertySource;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -524,6 +527,29 @@ public class MapBinderTests {
assertThat(foo.get().getFoos().get("foo2").getValue()).isEqualTo("three");
}
@Test
public void bindToMapWithCustomConverter() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new MapConverter());
Binder binder = new Binder(this.sources, null, conversionService);
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo", "a,b");
this.sources.add(source);
Map<String, String> map = binder.bind("foo", STRING_STRING_MAP).get();
assertThat(map.get("a")).isNotNull();
assertThat(map.get("b")).isNotNull();
}
@Test
public void bindToMapWithNoConverterForValue() {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo", "a,b");
this.sources.add(source);
BindResult<Map<String, String>> result = this.binder.bind("foo", STRING_STRING_MAP);
assertThat(result.isBound()).isFalse();
}
private <K, V> Bindable<Map<K, V>> getMapBindable(Class<K> keyGeneric,
ResolvableType valueType) {
ResolvableType keyType = ResolvableType.forClass(keyGeneric);
@ -576,4 +602,13 @@ public class MapBinderTests {
}
static class MapConverter implements Converter<String, Map<String, String>> {
@Override
public Map<String, String> convert(String s) {
Map<String, String> map = new HashMap<>();
StringUtils.commaDelimitedListToSet(s).forEach(k -> map.put(k, ""));
return map;
}
}
}

Loading…
Cancel
Save