From d8e52c04135474821d5d063d75a37ef1ea4f56b0 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Fri, 22 Sep 2017 12:38:12 +0200 Subject: [PATCH] Refine BeanUtils#findPrimaryConstructor behavior Issue: SPR-15673 --- .../org/springframework/beans/BeanUtils.java | 32 +++++++------ .../beans/BeanUtilsKotlinTests.kt | 45 +++++++++++++++++++ 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index 73e358c0d7..cfd19018f7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -332,9 +332,12 @@ public abstract class BeanUtils { } /** - * Return the primary constructor of the provided class (single or default constructor - * for Java classes and primary constructor for Kotlin classes), if any. - * @param clazz the {@link Class} of the Kotlin class + * Return the primary constructor of the provided class. For Java classes, it returns + * the single or the default constructor if any. For Kotlin classes, it returns the Java + * constructor corresponding to the Kotlin primary constructor (as defined in + * Kotlin specification), the single or the default constructor if any. + * + * @param clazz the class to check * @since 5.0 * @see Kotlin docs */ @@ -343,20 +346,21 @@ public abstract class BeanUtils { public static Constructor findPrimaryConstructor(Class clazz) { Assert.notNull(clazz, "Class must not be null"); if (useKotlinSupport(clazz)) { - return KotlinDelegate.findPrimaryConstructor(clazz); + Constructor kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz); + if (kotlinPrimaryConstructor != null) { + return kotlinPrimaryConstructor; + } + } + Constructor[] ctors = (Constructor[]) clazz.getConstructors(); + if (ctors.length == 1) { + return ctors[0]; } else { - Constructor[] ctors = (Constructor[]) clazz.getConstructors(); - if (ctors.length == 1) { - return ctors[0]; + try { + return clazz.getDeclaredConstructor(); } - else { - try { - return clazz.getDeclaredConstructor(); - } - catch (NoSuchMethodException ex) { - return null; - } + catch (NoSuchMethodException ex) { + return null; } } } diff --git a/spring-beans/src/test/kotlin/org/springframework/beans/BeanUtilsKotlinTests.kt b/spring-beans/src/test/kotlin/org/springframework/beans/BeanUtilsKotlinTests.kt index 0cfa1db216..dd19bce123 100644 --- a/spring-beans/src/test/kotlin/org/springframework/beans/BeanUtilsKotlinTests.kt +++ b/spring-beans/src/test/kotlin/org/springframework/beans/BeanUtilsKotlinTests.kt @@ -24,6 +24,7 @@ import org.junit.Test * * @author Sebastien Deleuze */ +@Suppress("unused", "UNUSED_PARAMETER") class BeanUtilsKotlinTests { @Test @@ -65,10 +66,54 @@ class BeanUtilsKotlinTests { assertEquals(12, baz.param2) } + @Test + fun `2 constructors with default one`() { + assertEquals(TwoConstructorsWithDefaultOne::class.java.getDeclaredConstructor(), BeanUtils.findPrimaryConstructor(TwoConstructorsWithDefaultOne::class.java)) + } + + @Test + fun `2 constructors without default one`() { + assertNull(BeanUtils.findPrimaryConstructor(TwoConstructorsWithoutDefaultOne::class.java)) + } + + @Test + fun `1 constructor with default one`() { + assertEquals(OneConstructorWithDefaultOne::class.java.getDeclaredConstructor(), BeanUtils.findPrimaryConstructor(OneConstructorWithDefaultOne::class.java)) + } + + @Test + fun `1 constructor without default one`() { + assertEquals(OneConstructorWithoutDefaultOne::class.java.getDeclaredConstructor(String::class.java), BeanUtils.findPrimaryConstructor(OneConstructorWithoutDefaultOne::class.java)) + } + class Foo(val param1: String, val param2: Int) class Bar(val param1: String, val param2: Int = 12) class Baz(var param1: String = "a", var param2: Int = 12) + class TwoConstructorsWithDefaultOne { + + constructor() + + constructor(param1: String) + } + + class TwoConstructorsWithoutDefaultOne { + + constructor(param1: String) + + constructor(param1: String, param2: String) + } + + class OneConstructorWithDefaultOne { + + constructor() + } + + class OneConstructorWithoutDefaultOne { + + constructor(param1: String) + } + }