From c99be7c2b0ac8241b23bad98871a2e64727a0258 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 11 May 2017 17:03:05 -0700 Subject: [PATCH] Properties treated as Map for bind Fixes gh-9152 --- .../boot/context/properties/bind/MapBinder.java | 12 +++++++++++- .../context/properties/bind/MapBinderTests.java | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java index 124468745a..2faa3e5680 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.properties.bind; import java.util.Collection; import java.util.Map; +import java.util.Properties; import org.springframework.boot.context.properties.bind.convert.BinderConversionService; import org.springframework.boot.context.properties.source.ConfigurationProperty; @@ -44,15 +45,24 @@ class MapBinder extends AggregateBinder> { protected Object bind(ConfigurationPropertyName name, Bindable target, AggregateElementBinder elementBinder, Class type) { Map map = CollectionFactory.createMap(type, 0); + Bindable resolvedTarget = resolveTarget(target); for (ConfigurationPropertySource source : getContext().getSources()) { if (!ConfigurationPropertyName.EMPTY.equals(name)) { source = source.filter(name::isAncestorOf); } - new EntryBinder(name, target, elementBinder).bindEntries(source, map); + new EntryBinder(name, resolvedTarget, elementBinder).bindEntries(source, map); } return (map.isEmpty() ? null : map); } + private Bindable resolveTarget(Bindable target) { + Class type = target.getType().resolve(); + if (Properties.class.isAssignableFrom(type)) { + return Bindable.mapOf(String.class, String.class); + } + return target; + } + @Override protected Map merge(Map existing, Map additional) { diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java index a022a66c12..e2ed99037c 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import org.junit.Before; import org.junit.Test; @@ -372,4 +373,19 @@ public class MapBinderTests { eq(target), any(), isA(Map.class)); } + @Test + public void bindToPropertiesShouldBeEquivalentToMapOfStringString() throws Exception { + this.sources + .add(new MockConfigurationPropertySource("foo.bar.baz", "1", "line1")); + BindHandler handler = mock(BindHandler.class, + withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS)); + Bindable target = Bindable.of(Properties.class); + this.binder.bind("foo", target, handler); + InOrder inOrder = inOrder(handler); + inOrder.verify(handler).onSuccess(eq(ConfigurationPropertyName.of("foo.bar.baz")), + eq(Bindable.of(String.class)), any(), eq("1")); + inOrder.verify(handler).onSuccess(eq(ConfigurationPropertyName.of("foo")), + eq(target), any(), isA(Properties.class)); + } + }