Skip to content

Commit d8e52c0

Browse files
committed
Refine BeanUtils#findPrimaryConstructor behavior
Issue: SPR-15673
1 parent 78434c8 commit d8e52c0

File tree

2 files changed

+63
-14
lines changed

2 files changed

+63
-14
lines changed

spring-beans/src/main/java/org/springframework/beans/BeanUtils.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,12 @@ else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
332332
}
333333

334334
/**
335-
* Return the primary constructor of the provided class (single or default constructor
336-
* for Java classes and primary constructor for Kotlin classes), if any.
337-
* @param clazz the {@link Class} of the Kotlin class
335+
* Return the primary constructor of the provided class. For Java classes, it returns
336+
* the single or the default constructor if any. For Kotlin classes, it returns the Java
337+
* constructor corresponding to the Kotlin primary constructor (as defined in
338+
* Kotlin specification), the single or the default constructor if any.
339+
*
340+
* @param clazz the class to check
338341
* @since 5.0
339342
* @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin docs</a>
340343
*/
@@ -343,20 +346,21 @@ else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
343346
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
344347
Assert.notNull(clazz, "Class must not be null");
345348
if (useKotlinSupport(clazz)) {
346-
return KotlinDelegate.findPrimaryConstructor(clazz);
349+
Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
350+
if (kotlinPrimaryConstructor != null) {
351+
return kotlinPrimaryConstructor;
352+
}
353+
}
354+
Constructor<T>[] ctors = (Constructor<T>[]) clazz.getConstructors();
355+
if (ctors.length == 1) {
356+
return ctors[0];
347357
}
348358
else {
349-
Constructor<T>[] ctors = (Constructor<T>[]) clazz.getConstructors();
350-
if (ctors.length == 1) {
351-
return ctors[0];
359+
try {
360+
return clazz.getDeclaredConstructor();
352361
}
353-
else {
354-
try {
355-
return clazz.getDeclaredConstructor();
356-
}
357-
catch (NoSuchMethodException ex) {
358-
return null;
359-
}
362+
catch (NoSuchMethodException ex) {
363+
return null;
360364
}
361365
}
362366
}

spring-beans/src/test/kotlin/org/springframework/beans/BeanUtilsKotlinTests.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import org.junit.Test
2424
*
2525
* @author Sebastien Deleuze
2626
*/
27+
@Suppress("unused", "UNUSED_PARAMETER")
2728
class BeanUtilsKotlinTests {
2829

2930
@Test
@@ -65,10 +66,54 @@ class BeanUtilsKotlinTests {
6566
assertEquals(12, baz.param2)
6667
}
6768

69+
@Test
70+
fun `2 constructors with default one`() {
71+
assertEquals(TwoConstructorsWithDefaultOne::class.java.getDeclaredConstructor(), BeanUtils.findPrimaryConstructor(TwoConstructorsWithDefaultOne::class.java))
72+
}
73+
74+
@Test
75+
fun `2 constructors without default one`() {
76+
assertNull(BeanUtils.findPrimaryConstructor(TwoConstructorsWithoutDefaultOne::class.java))
77+
}
78+
79+
@Test
80+
fun `1 constructor with default one`() {
81+
assertEquals(OneConstructorWithDefaultOne::class.java.getDeclaredConstructor(), BeanUtils.findPrimaryConstructor(OneConstructorWithDefaultOne::class.java))
82+
}
83+
84+
@Test
85+
fun `1 constructor without default one`() {
86+
assertEquals(OneConstructorWithoutDefaultOne::class.java.getDeclaredConstructor(String::class.java), BeanUtils.findPrimaryConstructor(OneConstructorWithoutDefaultOne::class.java))
87+
}
88+
6889
class Foo(val param1: String, val param2: Int)
6990

7091
class Bar(val param1: String, val param2: Int = 12)
7192

7293
class Baz(var param1: String = "a", var param2: Int = 12)
7394

95+
class TwoConstructorsWithDefaultOne {
96+
97+
constructor()
98+
99+
constructor(param1: String)
100+
}
101+
102+
class TwoConstructorsWithoutDefaultOne {
103+
104+
constructor(param1: String)
105+
106+
constructor(param1: String, param2: String)
107+
}
108+
109+
class OneConstructorWithDefaultOne {
110+
111+
constructor()
112+
}
113+
114+
class OneConstructorWithoutDefaultOne {
115+
116+
constructor(param1: String)
117+
}
118+
74119
}

0 commit comments

Comments
 (0)