Commit 0fbb4989 authored by Phillip Webb's avatar Phillip Webb

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
parent 5fb91628
......@@ -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.
......
......@@ -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(
......
......@@ -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,
......
......@@ -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
......
......@@ -351,6 +351,7 @@ public class CollectionBinderTests {
assertThat(result.getItemsSet()).containsExactly("a", "b", "c");
}
@Test
public void bindToBeanWithNestedCollectionShouldPopulateCollection()
throws Exception {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment