@@ -3,11 +3,14 @@ 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
16
@@ -38,7 +41,8 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
38
41
private val javaConstructorIsCreatorAnnotated = LRUMap <AnnotatedConstructor , Boolean >(reflectionCacheSize, reflectionCacheSize)
39
42
private val javaMemberIsRequired = LRUMap <AnnotatedMember , BooleanTriState ?>(reflectionCacheSize, reflectionCacheSize)
40
43
private val kotlinGeneratedMethod = LRUMap <AnnotatedMethod , Boolean >(reflectionCacheSize, reflectionCacheSize)
41
-
44
+ private val javaConstructorToInstantiator = LRUMap <Constructor <Any >, ConstructorInstantiator <Any >>(reflectionCacheSize, reflectionCacheSize)
45
+ private val javaMethodToInstantiator = LRUMap <Method , MethodInstantiator <* >>(reflectionCacheSize, reflectionCacheSize)
42
46
43
47
fun kotlinFromJava (key : Class <Any >): KClass <Any > = javaClassToKotlin.get(key)
44
48
? : key.kotlin.let { javaClassToKotlin.putIfAbsent(key, it) ? : it }
@@ -57,4 +61,58 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
57
61
58
62
fun isKotlinGeneratedMethod (key : AnnotatedMethod , calc : (AnnotatedMethod ) -> Boolean ): Boolean = kotlinGeneratedMethod.get(key)
59
63
? : calc(key).let { kotlinGeneratedMethod.putIfAbsent(key, it) ? : it }
64
+
65
+ private fun instantiatorFromJavaConstructor (key : Constructor <Any >): ConstructorInstantiator <* >? = javaConstructorToInstantiator.get(key)
66
+ ? : kotlinFromJava(key)?.let {
67
+ val instantiator = ConstructorInstantiator (it, key)
68
+ javaConstructorToInstantiator.putIfAbsent(key, instantiator) ? : instantiator
69
+ }
70
+
71
+ private fun instantiatorFromJavaMethod (key : Method ): MethodInstantiator <* >? = javaMethodToInstantiator.get(key)
72
+ ? : kotlinFromJava(key)?.takeIf {
73
+ // we shouldn't have an instance or receiver parameter and if we do, just go with default Java-ish behavior
74
+ it.extensionReceiverParameter == null
75
+ }?.let { callable ->
76
+ var companionInstance: Any? = null
77
+ var companionAccessible: Boolean? = null
78
+
79
+ callable.instanceParameter!! .type.erasedType().kotlin
80
+ .takeIf { it.isCompanion } // abort, we have some unknown case here
81
+ ?.let { possibleCompanion ->
82
+ try {
83
+ companionInstance = possibleCompanion.objectInstance
84
+ companionAccessible = true
85
+ } catch (ex: IllegalAccessException ) {
86
+ // fallback for when an odd access exception happens through Kotlin reflection
87
+ possibleCompanion.java.enclosingClass.fields
88
+ .firstOrNull { it.type.kotlin.isCompanion }
89
+ ?.let {
90
+ companionAccessible = it.isAccessible
91
+ it.isAccessible = true
92
+
93
+ companionInstance = it.get(null )
94
+ } ? : throw ex
95
+ }
96
+ }
97
+
98
+ companionInstance?.let {
99
+ MethodInstantiator (callable, key, it, companionAccessible!! ).run {
100
+ javaMethodToInstantiator.putIfAbsent(key, this ) ? : this
101
+ }
102
+ }
103
+ }
104
+
105
+ /*
106
+ * return null if...
107
+ * - can't get kotlinFunction
108
+ * - contains extensionReceiverParameter
109
+ * - instance parameter is not companion object or can't get
110
+ */
111
+ @Suppress(" UNCHECKED_CAST" )
112
+ fun instantiatorFromJava (_withArgsCreator : AnnotatedWithParams ): Instantiator <* >? = when (_withArgsCreator ) {
113
+ is AnnotatedConstructor -> instantiatorFromJavaConstructor(_withArgsCreator .annotated as Constructor <Any >)
114
+ is AnnotatedMethod -> instantiatorFromJavaMethod(_withArgsCreator .annotated as Method )
115
+ else ->
116
+ throw IllegalStateException (" Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator .annotated.javaClass.name} " )
117
+ }
60
118
}
0 commit comments