Skip to content

Commit 69cb68f

Browse files
committed
Add Kotlin data class components support to BindingReflectionHintsRegistrar
Closes gh-29316
1 parent 581fa14 commit 69cb68f

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.LinkedHashSet;
2323
import java.util.Set;
2424

25+
import kotlin.jvm.JvmClassMappingKt;
26+
import kotlin.reflect.KClass;
2527
import org.apache.commons.logging.Log;
2628
import org.apache.commons.logging.LogFactory;
2729

@@ -101,6 +103,7 @@ else if ((methodName.startsWith("get") && method.getParameterCount() == 0 && met
101103
}
102104
}
103105
if (KotlinDetector.isKotlinType(clazz)) {
106+
KotlinDelegate.registerComponentHints(hints, clazz);
104107
registerKotlinSerializationHints(hints, clazz);
105108
}
106109
});
@@ -148,4 +151,22 @@ private void collectReferencedTypes(Set<Class<?>> types, ResolvableType resolvab
148151
}
149152
}
150153

154+
/**
155+
* Inner class to avoid a hard dependency on Kotlin at runtime.
156+
*/
157+
private static class KotlinDelegate {
158+
159+
public static void registerComponentHints(ReflectionHints hints, Class<?> type) {
160+
KClass<?> kClass = JvmClassMappingKt.getKotlinClass(type);
161+
if (kClass.isData()) {
162+
for (Method method : type.getMethods()) {
163+
String methodName = method.getName();
164+
if (methodName.startsWith("component") || methodName.equals("copy")) {
165+
hints.registerMethod(method, ExecutableMode.INVOKE);
166+
}
167+
}
168+
}
169+
}
170+
}
171+
151172
}

spring-core/src/test/kotlin/org/springframework/aot/hint/KotlinBindingReflectionHintsRegistrarTests.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package org.springframework.aot.hint
1919
import org.assertj.core.api.Assertions.assertThat
2020
import org.assertj.core.api.ThrowingConsumer
2121
import org.junit.jupiter.api.Test
22+
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates
2223

2324
/**
2425
* Tests for Kotlin support in [BindingReflectionHintsRegistrar].
@@ -32,7 +33,7 @@ class KotlinBindingReflectionHintsRegistrarTests {
3233
private val hints = RuntimeHints()
3334

3435
@Test
35-
fun `Register type for Kotlinx serialization`() {
36+
fun `Register reflection hints for Kotlinx serialization`() {
3637
bindingRegistrar.registerReflectionHints(hints.reflection(), SampleSerializableClass::class.java)
3738
assertThat(hints.reflection().typeHints()).satisfiesExactlyInAnyOrder(
3839
ThrowingConsumer { typeHint: TypeHint ->
@@ -59,7 +60,17 @@ class KotlinBindingReflectionHintsRegistrarTests {
5960
})
6061
})
6162
}
63+
64+
@Test
65+
fun `Register reflection hints for Kotlin data class`() {
66+
bindingRegistrar.registerReflectionHints(hints.reflection(), SampleDataClass::class.java)
67+
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "component1")).accepts(hints)
68+
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "copy")).accepts(hints)
69+
assertThat(RuntimeHintsPredicates.reflection().onMethod(SampleDataClass::class.java, "getName")).accepts(hints)
70+
}
6271
}
6372

6473
@kotlinx.serialization.Serializable
6574
class SampleSerializableClass(val name: String)
75+
76+
data class SampleDataClass(val name: String)

0 commit comments

Comments
 (0)