Duplicate values should bind properly to List
Fixes gh-10106
This commit is contained in:
parent
0f25dd0ea6
commit
4a740a16f3
|
|
@ -19,7 +19,6 @@ package org.springframework.boot.context.properties.bind;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Internal strategy used by {@link Binder} to bind aggregates (Maps, Lists, Arrays).
|
||||
|
|
@ -47,9 +46,7 @@ abstract class AggregateBinder<T> {
|
|||
public final Object bind(ConfigurationPropertyName name, Bindable<?> target,
|
||||
AggregateElementBinder itemBinder) {
|
||||
Supplier<?> value = target.getValue();
|
||||
Class<?> type = (value == null ? target.getType().resolve()
|
||||
: ResolvableType.forClass(AggregateBinder.class, getClass())
|
||||
.resolveGeneric());
|
||||
Class<?> type = (value == null ? target.getType().resolve() : null);
|
||||
Object result = bind(name, target, itemBinder, type);
|
||||
if (result == null || value == null || value.get() == null) {
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.context.properties.bind;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
|
|
@ -37,10 +38,12 @@ class CollectionBinder extends IndexedElementsBinder<Collection<Object>> {
|
|||
@Override
|
||||
protected Object bind(ConfigurationPropertyName name, Bindable<?> target,
|
||||
AggregateElementBinder elementBinder, Class<?> type) {
|
||||
Class<?> collectionType = (type != null ? type
|
||||
: ResolvableType.forClassWithGenerics(List.class, Object.class).resolve());
|
||||
IndexedCollectionSupplier collection = new IndexedCollectionSupplier(
|
||||
() -> CollectionFactory.createCollection(type, 0));
|
||||
() -> CollectionFactory.createCollection(collectionType, 0));
|
||||
ResolvableType elementType = target.getType().asCollection().getGeneric();
|
||||
bindIndexed(name, target, elementBinder, collection, target.getType(),
|
||||
bindIndexed(name, target, elementBinder, collection, ResolvableType.forClass(collectionType),
|
||||
elementType);
|
||||
if (collection.wasSupplied()) {
|
||||
return collection.get();
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ class MapBinder extends AggregateBinder<Map<Object, Object>> {
|
|||
@Override
|
||||
protected Object bind(ConfigurationPropertyName name, Bindable<?> target,
|
||||
AggregateElementBinder elementBinder, Class<?> type) {
|
||||
Map<Object, Object> map = CollectionFactory.createMap(type, 0);
|
||||
Class<?> mapType = (type != null ? type
|
||||
: ResolvableType.forClassWithGenerics(Map.class, Object.class, Object.class).resolve());
|
||||
Map<Object, Object> map = CollectionFactory.createMap(mapType, 0);
|
||||
Bindable<?> resolvedTarget = resolveTarget(target);
|
||||
for (ConfigurationPropertySource source : getContext().getSources()) {
|
||||
if (!ConfigurationPropertyName.EMPTY.equals(name)) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.context.properties.bind;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
|
@ -316,10 +317,45 @@ public class CollectionBinderTests {
|
|||
assertThat(result.getItems()).containsExactly("a", "b", "c", "d");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToCollectionWithNoDefaultConstructor() throws Exception {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.items", "a,b,c,c");
|
||||
this.sources.add(source);
|
||||
ExampleCustomBean result = this.binder
|
||||
.bind("foo", ExampleCustomBean.class).get();
|
||||
assertThat(result.getItems()).hasSize(4);
|
||||
assertThat(result.getItems()).containsExactly("a", "b", "c", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToListShouldAllowDuplicateValues() throws Exception {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.items", "a,b,c,c");
|
||||
this.sources.add(source);
|
||||
ExampleCollectionBean result = this.binder
|
||||
.bind("foo", ExampleCollectionBean.class).get();
|
||||
assertThat(result.getItems()).hasSize(5);
|
||||
assertThat(result.getItems()).containsExactly("a", "b", "c", "c", "d");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToSetShouldNotAllowDuplicateValues() throws Exception {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.items-set", "a,b,c,c");
|
||||
this.sources.add(source);
|
||||
ExampleCollectionBean result = this.binder
|
||||
.bind("foo", ExampleCollectionBean.class).get();
|
||||
assertThat(result.getItemsSet()).hasSize(3);
|
||||
assertThat(result.getItemsSet()).containsExactly("a", "b", "c");
|
||||
}
|
||||
|
||||
public static class ExampleCollectionBean {
|
||||
|
||||
private List<String> items = new ArrayList<>();
|
||||
|
||||
private Set<String> itemsSet = new HashSet<>();
|
||||
|
||||
public List<String> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
|
@ -328,6 +364,36 @@ public class CollectionBinderTests {
|
|||
this.items.add("d");
|
||||
}
|
||||
|
||||
public Set<String> getItemsSet() {
|
||||
return this.itemsSet;
|
||||
}
|
||||
|
||||
public void setItemsSet(Set<String> itemsSet) {
|
||||
this.itemsSet = itemsSet;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExampleCustomBean {
|
||||
|
||||
private MyCustomList items = new MyCustomList(Collections.singletonList("foo"));
|
||||
|
||||
public MyCustomList getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public void setItems(MyCustomList items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyCustomList extends ArrayList {
|
||||
|
||||
private List<String> items = new ArrayList<>(Collections.singletonList("foo"));
|
||||
|
||||
public MyCustomList(List<String> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue