Skip to content

Commit 8ce13c7

Browse files
committed
Support binding to immutable maps
Closes gh-13323
1 parent 68cd27c commit 8ce13c7

File tree

2 files changed

+32
-6
lines changed
  • spring-boot-project/spring-boot/src

2 files changed

+32
-6
lines changed

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,32 @@ protected Map<Object, Object> merge(Supplier<?> existing,
9090
if (existingMap == null) {
9191
return additional;
9292
}
93-
existingMap.putAll(additional);
94-
return copyIfPossible(existingMap);
93+
try {
94+
existingMap.putAll(additional);
95+
return copyIfPossible(existingMap);
96+
}
97+
catch (UnsupportedOperationException ex) {
98+
Map<Object, Object> result = createNewMap(additional.getClass(), existingMap);
99+
result.putAll(additional);
100+
return result;
101+
}
95102
}
96103

97104
private Map<Object, Object> copyIfPossible(Map<Object, Object> map) {
98105
try {
99-
Map<Object, Object> result = CollectionFactory.createMap(map.getClass(),
100-
map.size());
101-
result.putAll(map);
102-
return result;
106+
return createNewMap(map.getClass(), map);
103107
}
104108
catch (Exception ex) {
105109
return map;
106110
}
107111
}
108112

113+
private Map<Object, Object> createNewMap(Class<?> mapClass, Map<Object, Object> map) {
114+
Map<Object, Object> result = CollectionFactory.createMap(mapClass, map.size());
115+
result.putAll(map);
116+
return result;
117+
}
118+
109119
private class EntryBinder {
110120

111121
private final ConfigurationPropertyName root;

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,22 @@ public void bindToMapWithDefaultConstructor() {
615615
assertThat(result.getItems()).containsExactly(entry("a", "b"));
616616
}
617617

618+
@Test
619+
public void bindToImmutableMapShouldReturnPopulatedCollection() {
620+
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
621+
source.put("foo.values.c", "d");
622+
source.put("foo.values.e", "f");
623+
this.sources.add(source);
624+
Map<String, String> result = this.binder
625+
.bind("foo.values",
626+
STRING_STRING_MAP
627+
.withExistingValue(Collections.singletonMap("a", "b")))
628+
.get();
629+
assertThat(result).hasSize(3);
630+
assertThat(result.entrySet()).containsExactly(entry("a", "b"), entry("c", "d"),
631+
entry("e", "f"));
632+
}
633+
618634
private <K, V> Bindable<Map<K, V>> getMapBindable(Class<K> keyGeneric,
619635
ResolvableType valueType) {
620636
ResolvableType keyType = ResolvableType.forClass(keyGeneric);

0 commit comments

Comments
 (0)