Skip to content

Commit 817debb

Browse files
committed
Fix constructor binding with conversion to custom collection type
Closes gh-37734
1 parent 7d6532c commit 817debb

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ class CollectionBinder extends IndexedElementsBinder<Collection<Object>> {
4040
@Override
4141
protected Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target,
4242
AggregateElementBinder elementBinder) {
43-
Class<?> collectionType = (target.getValue() != null) ? List.class : target.getType().resolve(Object.class);
4443
ResolvableType aggregateType = ResolvableType.forClassWithGenerics(List.class,
4544
target.getType().asCollection().getGenerics());
4645
ResolvableType elementType = target.getType().asCollection().getGeneric();
4746
IndexedCollectionSupplier result = new IndexedCollectionSupplier(
48-
() -> CollectionFactory.createCollection(collectionType, elementType.resolve(), 0));
47+
() -> CollectionFactory.createCollection(List.class, elementType.resolve(), 0));
4948
bindIndexed(name, target, elementBinder, aggregateType, elementType, result);
5049
if (result.wasSupplied()) {
5150
return result.get();

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,19 @@ void loadWhenBindingWithCustomConverterAndObjectToObjectMethod() {
11171117
assertThat(bean.getItem().getValue()).isEqualTo("foo");
11181118
}
11191119

1120+
@Test
1121+
void loadWhenBindingToConstructorParametersWithConversionToCustomListImplementation() {
1122+
load(ConstructorBoundCustomListPropertiesConfiguration.class, "test.values=a,b");
1123+
assertThat(this.context.getBean(ConstructorBoundCustomListProperties.class).getValues()).containsExactly("a",
1124+
"b");
1125+
}
1126+
1127+
@Test
1128+
void loadWhenBindingToJavaBeanWithConversionToCustomListImplementation() {
1129+
load(SetterBoundCustomListPropertiesConfiguration.class, "test.values=a,b");
1130+
assertThat(this.context.getBean(SetterBoundCustomListProperties.class).getValues()).containsExactly("a", "b");
1131+
}
1132+
11201133
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
11211134
return load(new Class<?>[] { configuration }, inlinedProperties);
11221135
}
@@ -2857,4 +2870,83 @@ public WithPublicObjectToObjectMethod convert(String source) {
28572870

28582871
}
28592872

2873+
@Configuration(proxyBeanMethods = false)
2874+
@EnableConfigurationProperties(ConstructorBoundCustomListProperties.class)
2875+
static class ConstructorBoundCustomListPropertiesConfiguration {
2876+
2877+
@Bean
2878+
@ConfigurationPropertiesBinding
2879+
static Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {
2880+
return new Converter<ArrayList<?>, CustomList<?>>() {
2881+
2882+
@Override
2883+
public CustomList<?> convert(ArrayList<?> source) {
2884+
return new CustomList<>(source);
2885+
}
2886+
2887+
};
2888+
2889+
}
2890+
2891+
}
2892+
2893+
@ConstructorBinding
2894+
@ConfigurationProperties("test")
2895+
static class ConstructorBoundCustomListProperties {
2896+
2897+
private final CustomList<String> values;
2898+
2899+
ConstructorBoundCustomListProperties(CustomList<String> values) {
2900+
this.values = values;
2901+
}
2902+
2903+
CustomList<String> getValues() {
2904+
return this.values;
2905+
}
2906+
2907+
}
2908+
2909+
@Configuration(proxyBeanMethods = false)
2910+
@EnableConfigurationProperties(SetterBoundCustomListProperties.class)
2911+
static class SetterBoundCustomListPropertiesConfiguration {
2912+
2913+
@Bean
2914+
@ConfigurationPropertiesBinding
2915+
static Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {
2916+
return new Converter<ArrayList<?>, CustomList<?>>() {
2917+
2918+
@Override
2919+
public CustomList<?> convert(ArrayList<?> source) {
2920+
return new CustomList<>(source);
2921+
}
2922+
2923+
};
2924+
2925+
}
2926+
2927+
}
2928+
2929+
@ConfigurationProperties("test")
2930+
static class SetterBoundCustomListProperties {
2931+
2932+
private CustomList<String> values;
2933+
2934+
CustomList<String> getValues() {
2935+
return this.values;
2936+
}
2937+
2938+
void setValues(CustomList<String> values) {
2939+
this.values = values;
2940+
}
2941+
2942+
}
2943+
2944+
static final class CustomList<E> extends ArrayList<E> {
2945+
2946+
CustomList(List<E> delegate) {
2947+
super(delegate);
2948+
}
2949+
2950+
}
2951+
28602952
}

0 commit comments

Comments
 (0)