Skip to content

Commit b1f23f5

Browse files
committed
Prevent ValueBinder from being incorrectly used
Fix a regression caused by e41c5a4 which incorrectly allowed the `ValueObjectBinder` to be picked when the `JavaBeanBinder` should have been used. Closes gh-18485
1 parent 5547a84 commit b1f23f5

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,12 @@ static <T> ValueObject<T> get(Class<T> type, Predicate<Constructor<?>> construct
203203
constructor = candidate;
204204
}
205205
}
206-
return (constructor != null) ? new DefaultValueObject<>((Constructor<T>) constructor) : null;
206+
return get((Constructor<T>) constructor);
207207
}
208208

209209
private static boolean isCandidateConstructor(Constructor<?> candidate, Predicate<Constructor<?>> filter) {
210210
int modifiers = candidate.getModifiers();
211-
return !Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)
212-
&& candidate.getParameterCount() > 0 && filter.test(candidate);
211+
return !Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers) && filter.test(candidate);
213212
}
214213

215214
static <T> DefaultValueObject<T> get(Constructor<T> constructor) {

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,35 @@ void loadWhenBindingToNestedConstructorPropertiesShouldBind() {
807807
assertThat(bean.getNested().getAge()).isEqualTo(5);
808808
}
809809

810+
@Test // gh-18485
811+
void loadWhenBindingToMultiConstructorConfigurationProperties() {
812+
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
813+
Map<String, Object> source = new HashMap<>();
814+
source.put("test.nested[0].name", "spring");
815+
source.put("test.nested[0].age", "5");
816+
sources.addLast(new MapPropertySource("test", source));
817+
load(MultiConstructorConfigurationPropertiesConfiguration.class);
818+
MultiConstructorConfigurationListProperties bean = this.context
819+
.getBean(MultiConstructorConfigurationListProperties.class);
820+
MultiConstructorConfigurationProperties nested = bean.getNested().get(0);
821+
assertThat(nested.getName()).isEqualTo("spring");
822+
assertThat(nested.getAge()).isEqualTo(5);
823+
}
824+
825+
@Test // gh-18485
826+
void loadWhenBindingToMultiConstructorConfigurationPropertiesUsingShortcutSyntax() {
827+
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
828+
Map<String, Object> source = new HashMap<>();
829+
source.put("test.nested[0]", "spring");
830+
sources.addLast(new MapPropertySource("test", source));
831+
load(MultiConstructorConfigurationPropertiesConfiguration.class);
832+
MultiConstructorConfigurationListProperties bean = this.context
833+
.getBean(MultiConstructorConfigurationListProperties.class);
834+
MultiConstructorConfigurationProperties nested = bean.getNested().get(0);
835+
assertThat(nested.getName()).isEqualTo("spring");
836+
assertThat(nested.getAge()).isEqualTo(0);
837+
}
838+
810839
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
811840
return load(new Class<?>[] { configuration }, inlinedProperties);
812841
}
@@ -1968,4 +1997,21 @@ int getAge() {
19681997

19691998
}
19701999

2000+
@ConfigurationProperties("test")
2001+
static class MultiConstructorConfigurationListProperties {
2002+
2003+
private List<MultiConstructorConfigurationProperties> nested = new ArrayList<>();
2004+
2005+
List<MultiConstructorConfigurationProperties> getNested() {
2006+
return this.nested;
2007+
}
2008+
2009+
}
2010+
2011+
@Configuration(proxyBeanMethods = false)
2012+
@EnableConfigurationProperties(MultiConstructorConfigurationListProperties.class)
2013+
static class MultiConstructorConfigurationPropertiesConfiguration {
2014+
2015+
}
2016+
19712017
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.context.properties;
18+
19+
/**
20+
* Class used to test multi-constructor binding. Must be public and have public
21+
* constructors.
22+
*
23+
* @author Phillip Webb
24+
*/
25+
public class MultiConstructorConfigurationProperties {
26+
27+
private String name;
28+
29+
private int age;
30+
31+
public MultiConstructorConfigurationProperties() {
32+
}
33+
34+
public MultiConstructorConfigurationProperties(String name) {
35+
this.name = name;
36+
}
37+
38+
public String getName() {
39+
return this.name;
40+
}
41+
42+
public void setName(String name) {
43+
this.name = name;
44+
}
45+
46+
public int getAge() {
47+
return this.age;
48+
}
49+
50+
public void setAge(int age) {
51+
this.age = age;
52+
}
53+
54+
}

0 commit comments

Comments
 (0)