diff --git a/pom.xml b/pom.xml
index 8576363d34..44e2893086 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-commons
- 3.3.0-SNAPSHOT
+ 3.3.x-3041-SNAPSHOT
Spring Data Core
Core Spring concepts underpinning every Spring Data module.
diff --git a/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java b/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java
index 0d5b7bf1ea..7823e69194 100644
--- a/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java
+++ b/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java
@@ -25,10 +25,12 @@
import kotlin.reflect.KProperty;
import kotlin.reflect.KType;
import kotlin.reflect.KTypeParameter;
+import kotlin.reflect.KTypeProjection;
import kotlin.reflect.jvm.ReflectJvmMapping;
import java.lang.reflect.Type;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -39,6 +41,7 @@
* Utilities for Kotlin Value class support.
*
* @author Mark Paluch
+ * @author Christoph Strobl
* @since 3.2
*/
class KotlinValueUtils {
@@ -72,7 +75,28 @@ public static ValueBoxing getConstructorValueHierarchy(KParameter parameter) {
public static ValueBoxing getConstructorValueHierarchy(Class> cls) {
KClass> kotlinClass = JvmClassMappingKt.getKotlinClass(cls);
- return new ValueBoxing(BoxingRules.CONSTRUCTOR, Reflection.typeOf(kotlinClass), kotlinClass, false);
+ KType kType = extractKType(kotlinClass);
+ return new ValueBoxing(BoxingRules.CONSTRUCTOR, kType, kotlinClass, false);
+ }
+
+ /**
+ * Get the {@link KType} for a given {@link KClass} and potentially fill missing generic type arguments with
+ * {@link KTypeProjection#star} to prevent Kotlin internal checks to fail.
+ *
+ * @param kotlinClass
+ * @return
+ */
+ private static KType extractKType(KClass> kotlinClass) {
+
+ return kotlinClass.getTypeParameters().isEmpty() ? Reflection.typeOf(kotlinClass)
+ : Reflection.typeOf(JvmClassMappingKt.getJavaClass(kotlinClass), stubKTypeProjections(kotlinClass));
+ }
+
+ private static KTypeProjection[] stubKTypeProjections(KClass> kotlinClass) {
+
+ KTypeProjection[] kTypeProjections = new KTypeProjection[kotlinClass.getTypeParameters().size()];
+ Arrays.fill(kTypeProjections, KTypeProjection.star);
+ return kTypeProjections;
}
/**
diff --git a/src/test/kotlin/org/springframework/data/mapping/model/KotlinClassGeneratingEntityInstantiatorUnitTests.kt b/src/test/kotlin/org/springframework/data/mapping/model/KotlinClassGeneratingEntityInstantiatorUnitTests.kt
index 5ee79c3495..0e8508f29b 100644
--- a/src/test/kotlin/org/springframework/data/mapping/model/KotlinClassGeneratingEntityInstantiatorUnitTests.kt
+++ b/src/test/kotlin/org/springframework/data/mapping/model/KotlinClassGeneratingEntityInstantiatorUnitTests.kt
@@ -21,8 +21,11 @@ import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Test
import org.springframework.data.annotation.PersistenceConstructor
+import org.springframework.data.annotation.Persistent
import org.springframework.data.mapping.PersistentEntity
import org.springframework.data.mapping.context.SamplePersistentProperty
+import org.springframework.data.mapping.model.KotlinValueUtils.BoxingRules
+import kotlin.jvm.internal.Reflection
import kotlin.reflect.KClass
/**
@@ -149,6 +152,28 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
assertThat(instance.aBool).isTrue()
}
+ @Test // GH-3041
+ fun `should pick preferred constructor if multiple with same argument count are present`() {
+
+ val entity =
+ mockk>()
+ val constructor =
+ PreferredConstructorDiscoverer.discover(
+ WithConstructorsHavingSameParameterCount::class.java
+ )
+
+ every { provider.getParameterValue(any()) }.returns(1L).andThen(null)
+ every { entity.instanceCreatorMetadata } returns constructor
+ every { entity.type } returns constructor!!.constructor.declaringClass
+ every { entity.typeInformation } returns mockk()
+
+ val instance: WithConstructorsHavingSameParameterCount =
+ KotlinClassGeneratingEntityInstantiator().createInstance(entity, provider)
+
+ assertThat(instance.id).isEqualTo(1L)
+ assertThat(instance.notes).isEmpty();
+ }
+
@Test // DATACMNS-1338
fun `should create instance using @PersistenceConstructor`() {
@@ -271,6 +296,11 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
val aFloat: Float = 0.0f, val aDouble: Double = 0.0, val aChar: Char = 'a', val aBool: Boolean = true
)
+
+ data class WithConstructorsHavingSameParameterCount @PersistenceConstructor constructor(val id: Long?, val notes: Map = emptyMap()) {
+ constructor(notes: Map, additionalNotes: Map = emptyMap()) : this(null, notes + additionalNotes)
+ }
+
data class ContactWithPersistenceConstructor(val firstname: String, val lastname: String) {
@PersistenceConstructor