@@ -3,14 +3,16 @@ package com.fasterxml.jackson.module.kotlin
3
3
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
4
4
import com.fasterxml.jackson.databind.introspect.AnnotatedMember
5
5
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
6
+ import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams
6
7
import com.fasterxml.jackson.databind.util.LRUMap
7
8
import java.lang.reflect.Constructor
8
9
import java.lang.reflect.Method
9
10
import kotlin.reflect.KClass
10
11
import kotlin.reflect.KFunction
12
+ import kotlin.reflect.full.extensionReceiverParameter
13
+ import kotlin.reflect.full.instanceParameter
11
14
import kotlin.reflect.jvm.kotlinFunction
12
15
13
-
14
16
internal class ReflectionCache (reflectionCacheSize : Int ) {
15
17
sealed class BooleanTriState (val value : Boolean? ) {
16
18
class True : BooleanTriState (true )
@@ -38,7 +40,8 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
38
40
private val javaConstructorIsCreatorAnnotated = LRUMap <AnnotatedConstructor , Boolean >(reflectionCacheSize, reflectionCacheSize)
39
41
private val javaMemberIsRequired = LRUMap <AnnotatedMember , BooleanTriState ?>(reflectionCacheSize, reflectionCacheSize)
40
42
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)
42
45
43
46
fun kotlinFromJava (key : Class <Any >): KClass <Any > = javaClassToKotlin.get(key)
44
47
? : key.kotlin.let { javaClassToKotlin.putIfAbsent(key, it) ? : it }
@@ -57,4 +60,58 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
57
60
58
61
fun isKotlinGeneratedMethod (key : AnnotatedMethod , calc : (AnnotatedMethod ) -> Boolean ): Boolean = kotlinGeneratedMethod.get(key)
59
62
? : 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
+ }
60
117
}
0 commit comments