Skip to content

Commit 090802b

Browse files
committed
Use existing value rather than deducing bind method
When there is an existing value, deducing the bind method may incorrectly result in the use of constructor binding. This results in a failure in the configuration properties post-processor as it refuses to bind properties to a bean whose attributes indicate that constructor binding should have been used. This commit updates ConfigurationPropertiesBean to avoid tryin to deduce the bind method and instead use the presence or absence of an existing value to determine the type of binding that should be used. Only when there is no existing value is constructor binding appropriate. Fixes gh-36175
1 parent 2a5a5d1 commit 090802b

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,6 @@ public static ConfigurationPropertiesBean get(ApplicationContext applicationCont
216216
if (bindTarget.getBindMethod() == null && factoryMethod != null) {
217217
bindTarget = bindTarget.withBindMethod(JAVA_BEAN_BIND_METHOD);
218218
}
219-
if (bindTarget.getBindMethod() == null) {
220-
bindTarget = bindTarget.withBindMethod(deduceBindMethod(bindTarget));
221-
}
222219
if (bindTarget.getBindMethod() != VALUE_OBJECT_BIND_METHOD) {
223220
bindTarget = bindTarget.withExistingValue(bean);
224221
}

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
7373
import org.springframework.context.annotation.Bean;
7474
import org.springframework.context.annotation.Configuration;
75+
import org.springframework.context.annotation.Import;
7576
import org.springframework.context.annotation.ImportResource;
7677
import org.springframework.context.annotation.Scope;
7778
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@@ -1152,6 +1153,14 @@ void loadWhenNestedRecordWithExistingInstance() {
11521153
assertThat(bean.getNested().name()).isEqualTo("spring");
11531154
}
11541155

1156+
@Test
1157+
void loadWhenPotentiallyConstructorBoundPropertiesAreImportedUsesJavaBeanBinding() {
1158+
load(PotentiallyConstructorBoundPropertiesImporter.class, "test.prop=alpha");
1159+
PotentiallyConstructorBoundProperties properties = this.context
1160+
.getBean(PotentiallyConstructorBoundProperties.class);
1161+
assertThat(properties.getProp()).isEqualTo("alpha");
1162+
}
1163+
11551164
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
11561165
return load(new Class<?>[] { configuration }, inlinedProperties);
11571166
}
@@ -3004,4 +3013,34 @@ void setNested(NestedRecord nestedRecord) {
30043013
static record NestedRecord(String name) {
30053014
}
30063015

3016+
@EnableConfigurationProperties
3017+
@Import(PotentiallyConstructorBoundProperties.class)
3018+
static class PotentiallyConstructorBoundPropertiesImporter {
3019+
3020+
@Bean
3021+
String notAProperty() {
3022+
return "notAProperty";
3023+
}
3024+
3025+
}
3026+
3027+
@ConfigurationProperties("test")
3028+
static class PotentiallyConstructorBoundProperties {
3029+
3030+
private String prop;
3031+
3032+
PotentiallyConstructorBoundProperties(String notAProperty) {
3033+
3034+
}
3035+
3036+
String getProp() {
3037+
return this.prop;
3038+
}
3039+
3040+
void setProp(String prop) {
3041+
this.prop = prop;
3042+
}
3043+
3044+
}
3045+
30073046
}

spring-boot-project/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/KotlinConfigurationPropertiesTests.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry
2222
import org.springframework.beans.factory.support.RootBeanDefinition
2323
import org.springframework.context.annotation.AnnotationConfigApplicationContext
2424
import org.springframework.context.annotation.Configuration
25+
import org.springframework.context.annotation.Import
2526
import org.springframework.test.context.support.TestPropertySourceUtils
2627

2728
import org.assertj.core.api.Assertions.assertThat
@@ -68,6 +69,14 @@ class KotlinConfigurationPropertiesTests {
6869
assertThat(properties.inner.bravo).isEqualTo("two")
6970
}
7071

72+
@Test
73+
fun `mutable data class properties can be imported`() {
74+
this.context.register(MutableDataClassPropertiesImporter::class.java)
75+
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, "mutable.prop=alpha");
76+
this.context.refresh();
77+
assertThat(this.context.getBean(MutableDataClassProperties::class.java).prop).isEqualTo("alpha")
78+
}
79+
7180
@ConfigurationProperties(prefix = "foo")
7281
class BingProperties(@Suppress("UNUSED_PARAMETER") bar: String) {
7382

@@ -106,4 +115,15 @@ class KotlinConfigurationPropertiesTests {
106115

107116
}
108117

118+
@EnableConfigurationProperties
119+
@Configuration(proxyBeanMethods = false)
120+
@Import(MutableDataClassProperties::class)
121+
class MutableDataClassPropertiesImporter {
122+
}
123+
124+
@ConfigurationProperties(prefix = "mutable")
125+
data class MutableDataClassProperties(
126+
var prop: String = ""
127+
)
128+
109129
}

0 commit comments

Comments
 (0)