Skip to content

Commit 6b8575b

Browse files
committed
Fix constructor binding to Kotlin data class with default values
Closes gh-32416
1 parent f9c341c commit 6b8575b

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import java.lang.reflect.Constructor;
2020
import java.util.Arrays;
2121

22+
import org.springframework.beans.BeanUtils;
2223
import org.springframework.beans.factory.annotation.Autowired;
2324
import org.springframework.boot.context.properties.bind.BindConstructorProvider;
2425
import org.springframework.boot.context.properties.bind.Bindable;
26+
import org.springframework.core.KotlinDetector;
2527
import org.springframework.core.annotation.MergedAnnotations;
2628
import org.springframework.util.Assert;
2729

@@ -94,6 +96,9 @@ static Constructors getConstructors(Class<?> type) {
9496
}
9597
bind = findAnnotatedConstructor(type, bind, candidate);
9698
}
99+
if (bind == null && !hasAutowiredConstructor && isKotlinType(type)) {
100+
bind = deduceKotlinBindConstructor(type);
101+
}
97102
return new Constructors(hasAutowiredConstructor, bind);
98103
}
99104

@@ -141,6 +146,18 @@ private static Constructor<?> findAnnotatedConstructor(Class<?> type, Constructo
141146
return constructor;
142147
}
143148

149+
private static boolean isKotlinType(Class<?> type) {
150+
return KotlinDetector.isKotlinPresent() && KotlinDetector.isKotlinType(type);
151+
}
152+
153+
private static Constructor<?> deduceKotlinBindConstructor(Class<?> type) {
154+
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(type);
155+
if (primaryConstructor != null && primaryConstructor.getParameterCount() > 0) {
156+
return primaryConstructor;
157+
}
158+
return null;
159+
}
160+
144161
}
145162

146163
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -113,6 +113,12 @@ class ConfigurationPropertiesBindConstructorProviderTests {
113113
}
114114
}
115115

116+
@Test
117+
fun `data class with default values should use constructor binding`() {
118+
val bindConstructor = this.constructorProvider.getBindConstructor(ConstructorBindingDataClassWithDefaultValues::class.java, false)
119+
assertThat(bindConstructor).isNotNull();
120+
}
121+
116122
@ConfigurationProperties(prefix = "foo")
117123
class FooProperties
118124

@@ -210,4 +216,7 @@ class ConfigurationPropertiesBindConstructorProviderTests {
210216

211217
}
212218

219+
@ConfigurationProperties(prefix = "bing")
220+
data class ConstructorBindingDataClassWithDefaultValues(val name: String = "Joan", val counter: Int = 42)
221+
213222
}

0 commit comments

Comments
 (0)