Skip to content

Commit 5406567

Browse files
committed
Nested Map should not bind to null
Fixes gh-9801
1 parent c81106b commit 5406567

File tree

2 files changed

+43
-9
lines changed
  • spring-boot/src
    • main/java/org/springframework/boot/context/properties/bind
    • test/java/org/springframework/boot/context/properties/bind

2 files changed

+43
-9
lines changed

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,10 @@ private Object bindBean(ConfigurationPropertyName name, Bindable<?> target,
298298
}
299299
BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(
300300
name.append(propertyName), propertyTarget, handler, context);
301-
Class<?> type = target.getType().resolve();
302-
if (context.hasBoundBean(type)) {
301+
if (context.isProcessingName(name)) {
303302
return null;
304303
}
305-
return context.withBean(type, () -> {
304+
return context.withName(name, () -> {
306305
Stream<?> boundBeans = BEAN_BINDERS.stream()
307306
.map((b) -> b.bind(name, target, context, propertyBinder));
308307
return boundBeans.filter(Objects::nonNull).findFirst().orElse(null);
@@ -353,7 +352,7 @@ final class Context implements BindContext {
353352
private final List<ConfigurationPropertySource> source = Arrays
354353
.asList((ConfigurationPropertySource) null);
355354

356-
private final Deque<Class<?>> beans = new ArrayDeque<>();
355+
private final Deque<ConfigurationPropertyName> names = new ArrayDeque<>();
357356

358357
private ConfigurationProperty configurationProperty;
359358

@@ -385,13 +384,13 @@ public <T> T withSource(ConfigurationPropertySource source,
385384
}
386385
}
387386

388-
public <T> T withBean(Class<?> bean, Supplier<T> supplier) {
389-
this.beans.push(bean);
387+
public <T> T withName(ConfigurationPropertyName name, Supplier<T> supplier) {
388+
this.names.push(name);
390389
try {
391390
return withIncreasedDepth(supplier);
392391
}
393392
finally {
394-
this.beans.pop();
393+
this.names.pop();
395394
}
396395
}
397396

@@ -421,8 +420,8 @@ public Stream<ConfigurationPropertySource> streamSources() {
421420
return StreamSupport.stream(Binder.this.sources.spliterator(), false);
422421
}
423422

424-
public boolean hasBoundBean(Class<?> bean) {
425-
return this.beans.contains(bean);
423+
public boolean isProcessingName(ConfigurationPropertyName name) {
424+
return this.names.contains(name);
426425
}
427426

428427
@Override

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.time.LocalDate;
2020
import java.util.ArrayList;
2121
import java.util.Collections;
22+
import java.util.LinkedHashMap;
2223
import java.util.List;
24+
import java.util.Map;
2325

2426
import org.assertj.core.matcher.AssertionMatcher;
2527
import org.junit.Before;
@@ -237,6 +239,19 @@ public void assertion(BindException ex) throws AssertionError {
237239
this.binder.bind("foo", target);
238240
}
239241

242+
@Test
243+
public void nestedMapsShouldNotBindToNull() throws Exception {
244+
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
245+
source.put("foo.value", "one");
246+
source.put("foo.foos.foo1.value", "two");
247+
source.put("foo.foos.foo2.value", "three");
248+
this.sources.add(source);
249+
BindResult<Foo> foo = this.binder.bind("foo", Foo.class);
250+
assertThat(foo.get().getValue()).isNotNull();
251+
assertThat(foo.get().getFoos().get("foo1").getValue()).isEqualTo("two");
252+
assertThat(foo.get().getFoos().get("foo2").getValue()).isEqualTo("three");
253+
}
254+
240255
public static class JavaBean {
241256

242257
private String value;
@@ -263,4 +278,24 @@ public enum ExampleEnum {
263278

264279
}
265280

281+
static class Foo {
282+
283+
private String value;
284+
285+
private Map<String, Foo> foos = new LinkedHashMap<>();
286+
287+
public Map<String, Foo> getFoos() {
288+
return this.foos;
289+
}
290+
291+
public String getValue() {
292+
return this.value;
293+
}
294+
295+
public void setValue(String value) {
296+
this.value = value;
297+
}
298+
299+
}
300+
266301
}

0 commit comments

Comments
 (0)