Skip to content

Commit 5845e0b

Browse files
committed
add Instantiator fetch and cache logic to ReflectionCache.
1 parent 194d1f3 commit 5845e0b

File tree

1 file changed

+59
-2
lines changed

1 file changed

+59
-2
lines changed

src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ package com.fasterxml.jackson.module.kotlin
33
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
44
import com.fasterxml.jackson.databind.introspect.AnnotatedMember
55
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
6+
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams
67
import com.fasterxml.jackson.databind.util.LRUMap
78
import java.lang.reflect.Constructor
89
import java.lang.reflect.Method
910
import kotlin.reflect.KClass
1011
import kotlin.reflect.KFunction
12+
import kotlin.reflect.full.extensionReceiverParameter
13+
import kotlin.reflect.full.instanceParameter
1114
import kotlin.reflect.jvm.kotlinFunction
1215

13-
1416
internal class ReflectionCache(reflectionCacheSize: Int) {
1517
sealed class BooleanTriState(val value: Boolean?) {
1618
class True : BooleanTriState(true)
@@ -38,7 +40,8 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
3840
private val javaConstructorIsCreatorAnnotated = LRUMap<AnnotatedConstructor, Boolean>(reflectionCacheSize, reflectionCacheSize)
3941
private val javaMemberIsRequired = LRUMap<AnnotatedMember, BooleanTriState?>(reflectionCacheSize, reflectionCacheSize)
4042
private val kotlinGeneratedMethod = LRUMap<AnnotatedMethod, Boolean>(reflectionCacheSize, reflectionCacheSize)
41-
43+
private val javaConstructorToInstantiator = LRUMap<Constructor<Any>, ConstructorInstantiator<Any>>(reflectionCacheSize, reflectionCacheSize)
44+
private val javaMethodToInstantiator = LRUMap<Method, MethodInstantiator<*>>(reflectionCacheSize, reflectionCacheSize)
4245

4346
fun kotlinFromJava(key: Class<Any>): KClass<Any> = javaClassToKotlin.get(key)
4447
?: key.kotlin.let { javaClassToKotlin.putIfAbsent(key, it) ?: it }
@@ -57,4 +60,58 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
5760

5861
fun isKotlinGeneratedMethod(key: AnnotatedMethod, calc: (AnnotatedMethod) -> Boolean): Boolean = kotlinGeneratedMethod.get(key)
5962
?: calc(key).let { kotlinGeneratedMethod.putIfAbsent(key, it) ?: it }
63+
64+
private fun instantiatorFromJavaConstructor(key: Constructor<Any>): ConstructorInstantiator<*>? = javaConstructorToInstantiator.get(key)
65+
?: kotlinFromJava(key)?.let {
66+
val instantiator = ConstructorInstantiator(it, key)
67+
javaConstructorToInstantiator.putIfAbsent(key, instantiator) ?: instantiator
68+
}
69+
70+
private fun instantiatorFromJavaMethod(key: Method): MethodInstantiator<*>? = javaMethodToInstantiator.get(key)
71+
?: kotlinFromJava(key)?.takeIf {
72+
// we shouldn't have an instance or receiver parameter and if we do, just go with default Java-ish behavior
73+
it.extensionReceiverParameter == null
74+
}?.let { callable ->
75+
var companionInstance: Any? = null
76+
var companionAccessible: Boolean? = null
77+
78+
callable.instanceParameter!!.type.erasedType().kotlin
79+
.takeIf { it.isCompanion } // abort, we have some unknown case here
80+
?.let { possibleCompanion ->
81+
try {
82+
companionInstance = possibleCompanion.objectInstance
83+
companionAccessible = true
84+
} catch (ex: IllegalAccessException) {
85+
// fallback for when an odd access exception happens through Kotlin reflection
86+
possibleCompanion.java.enclosingClass.fields
87+
.firstOrNull { it.type.kotlin.isCompanion }
88+
?.let {
89+
companionAccessible = it.isAccessible
90+
it.isAccessible = true
91+
92+
companionInstance = it.get(null)
93+
} ?: throw ex
94+
}
95+
}
96+
97+
companionInstance?.let {
98+
MethodInstantiator(callable, key, it, companionAccessible!!).run {
99+
javaMethodToInstantiator.putIfAbsent(key, this) ?: this
100+
}
101+
}
102+
}
103+
104+
/*
105+
* return null if...
106+
* - can't get kotlinFunction
107+
* - contains extensionReceiverParameter
108+
* - instance parameter is not companion object or can't get
109+
*/
110+
@Suppress("UNCHECKED_CAST")
111+
fun instantiatorFromJava(_withArgsCreator: AnnotatedWithParams): Instantiator<*>? = when (_withArgsCreator) {
112+
is AnnotatedConstructor -> instantiatorFromJavaConstructor(_withArgsCreator.annotated as Constructor<Any>)
113+
is AnnotatedMethod -> instantiatorFromJavaMethod(_withArgsCreator.annotated as Method)
114+
else ->
115+
throw IllegalStateException("Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator.annotated.javaClass.name}")
116+
}
60117
}

0 commit comments

Comments
 (0)