Fix binding to bean with cloned arrays
Fixes gh-12478
This commit is contained in:
@@ -57,10 +57,10 @@ abstract class AggregateBinder<T> {
|
||||
AggregateElementBinder elementBinder) {
|
||||
Object result = bindAggregate(name, target, elementBinder);
|
||||
Supplier<?> value = target.getValue();
|
||||
if (result == null || value == null || value.get() == null) {
|
||||
if (result == null || value == null) {
|
||||
return result;
|
||||
}
|
||||
return merge((T) value.get(), (T) result);
|
||||
return merge(value, (T) result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,11 +75,11 @@ abstract class AggregateBinder<T> {
|
||||
|
||||
/**
|
||||
* Merge any additional elements into the existing aggregate.
|
||||
* @param existing the existing value
|
||||
* @param existing the supplier for the existing value
|
||||
* @param additional the additional elements to merge
|
||||
* @return the merged result
|
||||
*/
|
||||
protected abstract T merge(T existing, T additional);
|
||||
protected abstract T merge(Supplier<?> existing, T additional);
|
||||
|
||||
/**
|
||||
* Return the context being used by this binder.
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Binder.Context;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
@@ -55,7 +56,7 @@ class ArrayBinder extends IndexedElementsBinder<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object merge(Object existing, Object additional) {
|
||||
protected Object merge(Supplier<?> existing, Object additional) {
|
||||
return additional;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.boot.context.properties.bind;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Binder.Context;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
@@ -54,12 +55,17 @@ class CollectionBinder extends IndexedElementsBinder<Collection<Object>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Object> merge(Collection<Object> existing,
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Collection<Object> merge(Supplier<?> existing,
|
||||
Collection<Object> additional) {
|
||||
Collection<Object> existingCollection = (Collection<Object>) existing.get();
|
||||
if (existingCollection == null) {
|
||||
return additional;
|
||||
}
|
||||
try {
|
||||
existing.clear();
|
||||
existing.addAll(additional);
|
||||
return existing;
|
||||
existingCollection.clear();
|
||||
existingCollection.addAll(additional);
|
||||
return existingCollection;
|
||||
}
|
||||
catch (UnsupportedOperationException ex) {
|
||||
return createNewCollection(additional);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Binder.Context;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationProperty;
|
||||
@@ -82,10 +83,15 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Object, Object> merge(Map<Object, Object> existing,
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<Object, Object> merge(Supplier<?> existing,
|
||||
Map<Object, Object> additional) {
|
||||
existing.putAll(additional);
|
||||
return existing;
|
||||
Map<Object, Object> existingMap = (Map<Object, Object>) existing.get();
|
||||
if (existingMap == null) {
|
||||
return additional;
|
||||
}
|
||||
existingMap.putAll(additional);
|
||||
return existingMap;
|
||||
}
|
||||
|
||||
private class EntryBinder {
|
||||
|
||||
@@ -384,6 +384,17 @@ public class CollectionBinderTests {
|
||||
this.binder.bind("foo", target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToBeanWithClonedArray() {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.bar[0]", "hello");
|
||||
this.sources.add(source);
|
||||
Bindable<ClonedArrayBean> target = Bindable
|
||||
.of(ClonedArrayBean.class);
|
||||
ClonedArrayBean bean = this.binder.bind("foo", target).get();
|
||||
assertThat(bean.getBar()).contains("hello");
|
||||
}
|
||||
|
||||
public static class ExampleCollectionBean {
|
||||
|
||||
private List<String> items = new ArrayList<>();
|
||||
@@ -457,4 +468,19 @@ public class CollectionBinderTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ClonedArrayBean {
|
||||
|
||||
private String[] bar;
|
||||
|
||||
public String[] getBar() {
|
||||
return this.bar.clone();
|
||||
}
|
||||
|
||||
public void setBar(String[] bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user