Merge branch 'gh-10702'

pull/10921/merge
Phillip Webb 7 years ago
commit 5fb9162875

@ -31,8 +31,15 @@ abstract class AggregateBinder<T> {
private final BindContext context;
AggregateBinder(BindContext context) {
private final boolean allowRecursiveBinding;
AggregateBinder(BindContext context, boolean allowRecursiveBinding) {
this.context = context;
this.allowRecursiveBinding = allowRecursiveBinding;
}
boolean isAllowRecursiveBinding() {
return this.allowRecursiveBinding;
}
/**

@ -188,13 +188,14 @@ public class Binder {
}
protected final <T> T bind(ConfigurationPropertyName name, Bindable<T> target,
BindHandler handler, Context context, boolean skipIfHasBoundBean) {
BindHandler handler, Context context, boolean allowRecursiveBinding) {
context.clearConfigurationProperty();
try {
if (!handler.onStart(name, target, context)) {
return null;
}
Object bound = bindObject(name, target, handler, context, skipIfHasBoundBean);
Object bound = bindObject(name, target, handler, context,
allowRecursiveBinding);
return handleBindResult(name, target, handler, context, bound);
}
catch (Exception ex) {
@ -232,7 +233,7 @@ public class Binder {
}
private <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target,
BindHandler handler, Context context, boolean skipIfHasBoundBean)
BindHandler handler, Context context, boolean allowRecursiveBinding)
throws Exception {
ConfigurationProperty property = findProperty(name, context);
if (property == null && containsNoDescendantOf(context.streamSources(), name)) {
@ -245,7 +246,7 @@ public class Binder {
if (property != null) {
return bindProperty(name, target, handler, context, property);
}
return bindBean(name, target, handler, context, skipIfHasBoundBean);
return bindBean(name, target, handler, context, allowRecursiveBinding);
}
private AggregateBinder<?> getAggregateBinder(Bindable<?> target, Context context) {
@ -266,7 +267,7 @@ public class Binder {
BindHandler handler, Context context, AggregateBinder<?> aggregateBinder) {
AggregateElementBinder elementBinder = (itemName, itemTarget, source) -> {
Supplier<?> supplier = () -> bind(itemName, itemTarget, handler, context,
false);
aggregateBinder.isAllowRecursiveBinding());
return context.withSource(source, supplier);
};
return context.withIncreasedDepth(
@ -290,15 +291,15 @@ public class Binder {
}
private Object bindBean(ConfigurationPropertyName name, Bindable<?> target,
BindHandler handler, Context context, boolean skipIfHasBoundBean) {
BindHandler handler, Context context, boolean allowRecursiveBinding) {
if (containsNoDescendantOf(context.streamSources(), name)
|| isUnbindableBean(name, target, context)) {
return null;
}
BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(
name.append(propertyName), propertyTarget, handler, context, true);
name.append(propertyName), propertyTarget, handler, context, false);
Class<?> type = target.getType().resolve();
if (skipIfHasBoundBean && context.hasBoundBean(type)) {
if (!allowRecursiveBinding && context.hasBoundBean(type)) {
return null;
}
return context.withBean(type, () -> {

@ -45,7 +45,7 @@ abstract class IndexedElementsBinder<T> extends AggregateBinder<T> {
private static final String INDEX_ZERO = "[0]";
IndexedElementsBinder(BindContext context) {
super(context);
super(context, false);
}
protected final void bindIndexed(ConfigurationPropertyName name, Bindable<?> target,

@ -41,7 +41,7 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
.mapOf(String.class, String.class);
MapBinder(BindContext context) {
super(context);
super(context, true);
}
@Override

@ -351,6 +351,32 @@ public class CollectionBinderTests {
assertThat(result.getItemsSet()).containsExactly("a", "b", "c");
}
public void bindToBeanWithNestedCollectionShouldPopulateCollection()
throws Exception {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo.value", "one");
source.put("foo.foos[0].value", "two");
source.put("foo.foos[1].value", "three");
this.sources.add(source);
Bindable<BeanWithNestedCollection> target = Bindable
.of(BeanWithNestedCollection.class);
BeanWithNestedCollection foo = this.binder.bind("foo", target).get();
assertThat(foo.getValue()).isNotNull();
assertThat(foo.getFoos().get(0).getValue()).isEqualTo("two");
assertThat(foo.getFoos().get(1).getValue()).isEqualTo("three");
}
@Test
public void bindToBeanWithNestedCollectionAndNonIterableSourceShouldNotFail()
throws Exception {
// gh-10702
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
this.sources.add(source.nonIterable());
Bindable<BeanWithNestedCollection> target = Bindable
.of(BeanWithNestedCollection.class);
this.binder.bind("foo", target);
}
public static class ExampleCollectionBean {
private List<String> items = new ArrayList<>();
@ -401,4 +427,27 @@ public class CollectionBinderTests {
}
public static class BeanWithNestedCollection {
private String value;
private List<BeanWithNestedCollection> foos;
public List<BeanWithNestedCollection> getFoos() {
return this.foos;
}
public void setFoos(List<BeanWithNestedCollection> foos) {
this.foos = foos;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
}

Loading…
Cancel
Save