Allow recursive list binding when iterable source

Further refine recursive binding rules so that Lists are supported when
the underlying source is iterable.

Close gh-10702
This commit is contained in:
Phillip Webb 2017-11-05 09:39:17 -08:00
parent 5fb9162875
commit 0fbb4989da
5 changed files with 25 additions and 10 deletions

View File

@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind;
import java.util.function.Supplier;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
/**
* Internal strategy used by {@link Binder} to bind aggregates (Maps, Lists, Arrays).
@ -31,16 +32,17 @@ abstract class AggregateBinder<T> {
private final BindContext context;
private final boolean allowRecursiveBinding;
AggregateBinder(BindContext context, boolean allowRecursiveBinding) {
AggregateBinder(BindContext context) {
this.context = context;
this.allowRecursiveBinding = allowRecursiveBinding;
}
boolean isAllowRecursiveBinding() {
return this.allowRecursiveBinding;
}
/**
* Determine if recursive binding is supported.
* @param source the configuration property source or {@code null} for all sources.
* @return if recursive binding is supported
*/
protected abstract boolean isAllowRecursiveBinding(
ConfigurationPropertySource source);
/**
* Perform binding for the aggregate.

View File

@ -266,8 +266,10 @@ public class Binder {
private <T> Object bindAggregate(ConfigurationPropertyName name, Bindable<T> target,
BindHandler handler, Context context, AggregateBinder<?> aggregateBinder) {
AggregateElementBinder elementBinder = (itemName, itemTarget, source) -> {
boolean allowRecursiveBinding = aggregateBinder
.isAllowRecursiveBinding(source);
Supplier<?> supplier = () -> bind(itemName, itemTarget, handler, context,
aggregateBinder.isAllowRecursiveBinding());
allowRecursiveBinding);
return context.withSource(source, supplier);
};
return context.withIncreasedDepth(

View File

@ -45,7 +45,12 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> {
private static final String INDEX_ZERO = "[0]";
IndexedElementsBinder(BindContext context) {
super(context, false);
super(context);
}
@Override
protected boolean isAllowRecursiveBinding(ConfigurationPropertySource source) {
return source == null || source instanceof IterableConfigurationPropertySource;
}
protected final void bindIndexed(ConfigurationPropertyName name, Bindable<?> target,

View File

@ -41,7 +41,12 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
.mapOf(String.class, String.class);
MapBinder(BindContext context) {
super(context, true);
super(context);
}
@Override
protected boolean isAllowRecursiveBinding(ConfigurationPropertySource source) {
return true;
}
@Override

View File

@ -351,6 +351,7 @@ public class CollectionBinderTests {
assertThat(result.getItemsSet()).containsExactly("a", "b", "c");
}
@Test
public void bindToBeanWithNestedCollectionShouldPopulateCollection()
throws Exception {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();