Fix BeanUtils#instantiateClass w/ Kotlin + noarg constructor

Issue: SPR-15851
This commit is contained in:
Sebastien Deleuze 2017-08-14 15:14:02 +02:00
parent f57e5584af
commit ef175d7ca6
2 changed files with 21 additions and 13 deletions

View File

@ -734,12 +734,11 @@ public abstract class BeanUtils {
* Instantiate a Kotlin class using the provided constructor. * Instantiate a Kotlin class using the provided constructor.
* @param ctor the constructor of the Kotlin class to instantiate * @param ctor the constructor of the Kotlin class to instantiate
* @param args the constructor arguments to apply (use null for unspecified parameter if needed) * @param args the constructor arguments to apply (use null for unspecified parameter if needed)
* @throws BeanInstantiationException if no primary constructor can be found
*/ */
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) { public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
KFunction<T> kotlinConstructor = ReflectJvmMapping.getKotlinFunction(ctor); KFunction<T> kotlinConstructor = ReflectJvmMapping.getKotlinFunction(ctor);
if (kotlinConstructor == null) { if (kotlinConstructor == null) {
throw new BeanInstantiationException(ctor.getDeclaringClass(), "No corresponding Kotlin constructor found"); return ctor.newInstance(args);
} }
List<KParameter> parameters = kotlinConstructor.getParameters(); List<KParameter> parameters = kotlinConstructor.getParameters();
Map<KParameter, Object> argParameters = new HashMap<>(parameters.size()); Map<KParameter, Object> argParameters = new HashMap<>(parameters.size());

View File

@ -29,37 +29,46 @@ class BeanUtilsKotlinTests {
@Test @Test
fun `Instantiate immutable class`() { fun `Instantiate immutable class`() {
val constructor = BeanUtils.findPrimaryConstructor(Foo::class.java)!! val constructor = BeanUtils.findPrimaryConstructor(Foo::class.java)!!
val foo = BeanUtils.instantiateClass(constructor, "bar", 3) val foo = BeanUtils.instantiateClass(constructor, "a", 3)
assertEquals("bar", foo.param1) assertEquals("a", foo.param1)
assertEquals(3, foo.param2) assertEquals(3, foo.param2)
} }
@Test @Test
fun `Instantiate immutable class with optional parameter and all parameters specified`() { fun `Instantiate immutable class with optional parameter and all parameters specified`() {
val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!! val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!!
val bar = BeanUtils.instantiateClass(constructor, "baz", 8) val bar = BeanUtils.instantiateClass(constructor, "a", 8)
assertEquals("baz", bar.param1) assertEquals("a", bar.param1)
assertEquals(8, bar.param2) assertEquals(8, bar.param2)
} }
@Test @Test
fun `Instantiate immutable class with optional parameter and only mandatory parameters specified by position`() { fun `Instantiate immutable class with optional parameter and only mandatory parameters specified by position`() {
val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!! val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!!
val bar = BeanUtils.instantiateClass(constructor, "baz") val bar = BeanUtils.instantiateClass(constructor, "a")
assertEquals("baz", bar.param1) assertEquals("a", bar.param1)
assertEquals(12, bar.param2) assertEquals(12, bar.param2)
} }
@Test @Test
fun `Instantiate immutable class with optional parameter specified with null value`() { fun `Instantiate immutable class with optional parameter specified with null value`() {
val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!! val constructor = BeanUtils.findPrimaryConstructor(Bar::class.java)!!
val bar = BeanUtils.instantiateClass(constructor, "baz", null) val bar = BeanUtils.instantiateClass(constructor, "a", null)
assertEquals("baz", bar.param1) assertEquals("a", bar.param1)
assertEquals(12, bar.param2) assertEquals(12, bar.param2)
} }
@Test // SPR-15851
fun `Instantiate mutable class with declared constructor and default values for all parameters`() {
val baz = BeanUtils.instantiateClass(Baz::class.java.getDeclaredConstructor())
assertEquals("a", baz.param1)
assertEquals(12, baz.param2)
}
class Foo(val param1: String, val param2: Int) class Foo(val param1: String, val param2: Int)
class Bar(val param1: String, val param2: Int = 12) class Bar(val param1: String, val param2: Int = 12)
class Baz(var param1: String = "a", var param2: Int = 12)
} }