Skip to content

Commit c320833

Browse files
committed
Fixes handling of ReflectionCache.
1 parent 4bd73bb commit c320833

File tree

4 files changed

+60
-78
lines changed

4 files changed

+60
-78
lines changed

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

-2
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,9 @@ class KotlinModule constructor (
7777
}
7878

7979
val cache = ReflectionCache(reflectionCacheSize)
80-
val cacheNew = ReflectionCacheNew(reflectionCacheSize)
8180

8281
context.addValueInstantiators(KotlinInstantiators(
8382
cache,
84-
cacheNew,
8583
nullToEmptyCollection,
8684
nullToEmptyMap,
8785
nullIsSameAsDefault,

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import kotlin.reflect.jvm.javaType
2626
internal class KotlinValueInstantiator(
2727
src: StdValueInstantiator,
2828
private val cache: ReflectionCache,
29-
private val cacheNew: ReflectionCacheNew,
3029
private val nullToEmptyCollection: Boolean,
3130
private val nullToEmptyMap: Boolean,
3231
private val nullIsSameAsDefault: Boolean,
@@ -38,7 +37,7 @@ internal class KotlinValueInstantiator(
3837
props: Array<out SettableBeanProperty>,
3938
buffer: PropertyValueBuffer
4039
): Any? {
41-
val instantiator: Instantiator<*> = cacheNew.instantiatorFromJava(_withArgsCreator)
40+
val instantiator: Instantiator<*> = cache.instantiatorFromJava(_withArgsCreator)
4241
?: return super.createFromObjectWith(ctxt, props, buffer) // we cannot reflect this method so do the default Java-ish behavior
4342

4443
val bucket = instantiator.generateBucket()
@@ -280,7 +279,6 @@ internal class KotlinValueInstantiator(
280279

281280
internal class KotlinInstantiators(
282281
private val cache: ReflectionCache,
283-
private val cacheNew: ReflectionCacheNew,
284282
private val nullToEmptyCollection: Boolean,
285283
private val nullToEmptyMap: Boolean,
286284
private val nullIsSameAsDefault: Boolean,
@@ -297,7 +295,6 @@ internal class KotlinInstantiators(
297295
KotlinValueInstantiator(
298296
defaultInstantiator,
299297
cache,
300-
cacheNew,
301298
nullToEmptyCollection,
302299
nullToEmptyMap,
303300
nullIsSameAsDefault,

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

+59-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ 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

1316

@@ -38,7 +41,8 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
3841
private val javaConstructorIsCreatorAnnotated = LRUMap<AnnotatedConstructor, Boolean>(reflectionCacheSize, reflectionCacheSize)
3942
private val javaMemberIsRequired = LRUMap<AnnotatedMember, BooleanTriState?>(reflectionCacheSize, reflectionCacheSize)
4043
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)
4246

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

5862
fun isKotlinGeneratedMethod(key: AnnotatedMethod, calc: (AnnotatedMethod) -> Boolean): Boolean = kotlinGeneratedMethod.get(key)
5963
?: 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+
}
60118
}

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

-71
This file was deleted.

0 commit comments

Comments
 (0)