mirror of
https://github.com/spring-projects/spring-data-commons.git
synced 2026-05-03 03:34:35 +01:00
Default generic type arguments when resolving KType from a Class.
We now fill up missing KTypeProjection arguments with star because the Kotlin Reflection.typeOf resolution fails if arguments are not provided. Closes #3041 Original pull request: #3048
This commit is contained in:
committed by
Mark Paluch
parent
75728ac0be
commit
9d73853244
@@ -25,10 +25,12 @@ import kotlin.reflect.KParameter;
|
||||
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 @@ import org.springframework.util.Assert;
|
||||
* Utilities for Kotlin Value class support.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 3.2
|
||||
*/
|
||||
class KotlinValueUtils {
|
||||
@@ -72,7 +75,28 @@ class KotlinValueUtils {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+30
@@ -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<PersistentEntity<WithConstructorsHavingSameParameterCount, SamplePersistentProperty>>()
|
||||
val constructor =
|
||||
PreferredConstructorDiscoverer.discover<WithConstructorsHavingSameParameterCount, SamplePersistentProperty>(
|
||||
WithConstructorsHavingSameParameterCount::class.java
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<Any>(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<String, String> = emptyMap()) {
|
||||
constructor(notes: Map<String, String>, additionalNotes: Map<String, String> = emptyMap()) : this(null, notes + additionalNotes)
|
||||
}
|
||||
|
||||
data class ContactWithPersistenceConstructor(val firstname: String, val lastname: String) {
|
||||
|
||||
@PersistenceConstructor
|
||||
|
||||
Reference in New Issue
Block a user