Support binding with multiple constructors
Update `DefaultBindConstructorProvider` so that binding to objects with multiple constructors is allowed, as long as there is only one non-public candidate. Closes gh-23117
This commit is contained in:
parent
cf9e85ca53
commit
c613d119f7
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.context.properties.bind;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
|
@ -42,6 +43,18 @@ class DefaultBindConstructorProvider implements BindConstructorProvider {
|
|||
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
|
||||
return constructors[0];
|
||||
}
|
||||
Constructor<?> constructor = null;
|
||||
for (Constructor<?> candidate : constructors) {
|
||||
if (!Modifier.isPrivate(candidate.getModifiers())) {
|
||||
if (constructor != null) {
|
||||
return null;
|
||||
}
|
||||
constructor = candidate;
|
||||
}
|
||||
}
|
||||
if (constructor != null && constructor.getParameterCount() > 0) {
|
||||
return constructor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,18 @@ class ValueObjectBinderTests {
|
|||
assertThat(bound).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindToClassWithMultipleConstructorsWhenOnlyOneIsNotPrivateShouldBind() {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.int-value", "12");
|
||||
this.sources.add(source);
|
||||
MultipleConstructorsOnlyOneNotPrivateBean bean = this.binder
|
||||
.bind("foo", Bindable.of(MultipleConstructorsOnlyOneNotPrivateBean.class)).get();
|
||||
bean = bean.withString("test");
|
||||
assertThat(bean.getIntValue()).isEqualTo(12);
|
||||
assertThat(bean.getStringValue()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindToClassShouldBindNested() {
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
|
@ -341,7 +353,6 @@ class ValueObjectBinderTests {
|
|||
Bindable<NamedParameter> target = Bindable.of(NamedParameter.class);
|
||||
NamedParameter bound = this.binder.bindOrCreate("test", target);
|
||||
assertThat(bound.getImportName()).isEqualTo("test");
|
||||
|
||||
}
|
||||
|
||||
private void noConfigurationProperty(BindException ex) {
|
||||
|
@ -417,6 +428,35 @@ class ValueObjectBinderTests {
|
|||
|
||||
}
|
||||
|
||||
static class MultipleConstructorsOnlyOneNotPrivateBean {
|
||||
|
||||
private final int intValue;
|
||||
|
||||
private final String stringValue;
|
||||
|
||||
MultipleConstructorsOnlyOneNotPrivateBean(int intValue) {
|
||||
this(intValue, 23L, "hello");
|
||||
}
|
||||
|
||||
private MultipleConstructorsOnlyOneNotPrivateBean(int intValue, long longValue, String stringValue) {
|
||||
this.intValue = intValue;
|
||||
this.stringValue = stringValue;
|
||||
}
|
||||
|
||||
int getIntValue() {
|
||||
return this.intValue;
|
||||
}
|
||||
|
||||
String getStringValue() {
|
||||
return this.stringValue;
|
||||
}
|
||||
|
||||
MultipleConstructorsOnlyOneNotPrivateBean withString(String stringValue) {
|
||||
return new MultipleConstructorsOnlyOneNotPrivateBean(this.intValue, 0, stringValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract static class ExampleAbstractBean {
|
||||
|
||||
private final String name;
|
||||
|
|
Loading…
Reference in New Issue