fix to use cache
MODIFY
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt
@@ -27,8 +27,7 @@ internal class KotlinValueInstantiator(
props: Array<out SettableBeanProperty>,
buffer: PropertyValueBuffer
): Any? {
- // TODO: cache ValueCreator
- val valueCreator: ValueCreator<*> = ValueCreator.of(_withArgsCreator, cache)
+ val valueCreator: ValueCreator<*> = cache.valueCreatorFromJava(_withArgsCreator)
?: return super.createFromObjectWith(ctxt, props, buffer)
val propCount: Int

MODIFY
src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt
src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt
@@ -3,6 +3,7 @@ package com.fasterxml.jackson.module.kotlin
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
import com.fasterxml.jackson.databind.introspect.AnnotatedMember
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
+import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams
import com.fasterxml.jackson.databind.util.LRUMap
import java.lang.reflect.Constructor
import java.lang.reflect.Method
@@ -35,6 +36,8 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
private val javaClassToKotlin = LRUMap<Class<Any>, KClass<Any>>(reflectionCacheSize, reflectionCacheSize)
private val javaConstructorToKotlin = LRUMap<Constructor<Any>, KFunction<Any>>(reflectionCacheSize, reflectionCacheSize)
private val javaMethodToKotlin = LRUMap<Method, KFunction<*>>(reflectionCacheSize, reflectionCacheSize)
+ private val javaConstructorToValueCreator = LRUMap<Constructor<Any>, ConstructorValueCreator<*>>(reflectionCacheSize, reflectionCacheSize)
+ private val javaMethodToValueCreator = LRUMap<Method, MethodValueCreator<*>>(reflectionCacheSize, reflectionCacheSize)
private val javaConstructorIsCreatorAnnotated = LRUMap<AnnotatedConstructor, Boolean>(reflectionCacheSize, reflectionCacheSize)
private val javaMemberIsRequired = LRUMap<AnnotatedMember, BooleanTriState?>(reflectionCacheSize, reflectionCacheSize)
private val kotlinGeneratedMethod = LRUMap<AnnotatedMethod, Boolean>(reflectionCacheSize, reflectionCacheSize)
@@ -49,6 +52,37 @@ internal class ReflectionCache(reflectionCacheSize: Int) {
fun kotlinFromJava(key: Method): KFunction<*>? = javaMethodToKotlin.get(key)
?: key.kotlinFunction?.let { javaMethodToKotlin.putIfAbsent(key, it) ?: it }
+ /**
+ * return null if...
+ * - can't get kotlinFunction
+ * - contains extensionReceiverParameter
+ * - instance parameter is not companion object or can't get
+ */
+ @Suppress("UNCHECKED_CAST")
+ fun valueCreatorFromJava(_withArgsCreator: AnnotatedWithParams): ValueCreator<*>? = when (_withArgsCreator) {
+ is AnnotatedConstructor -> {
+ val constructor = _withArgsCreator.annotated as Constructor<Any>
+
+ javaConstructorToValueCreator.get(constructor)
+ ?: kotlinFromJava(constructor)?.let {
+ val value = ConstructorValueCreator(it)
+
+ javaConstructorToValueCreator.putIfAbsent(constructor, value) ?: value
+ }
+ }
+ is AnnotatedMethod -> {
+ val method = _withArgsCreator.annotated as Method
+
+ javaMethodToValueCreator.get(method)
+ ?: kotlinFromJava(method)?.let {
+ val value = MethodValueCreator.of(it)
+
+ javaMethodToValueCreator.putIfAbsent(method, value) ?: value
+ }
+ }
+ else -> throw IllegalStateException("Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator.annotated.javaClass.name}")
+ } // we cannot reflect this method so do the default Java-ish behavior
+
fun checkConstructorIsCreatorAnnotated(key: AnnotatedConstructor, calc: (AnnotatedConstructor) -> Boolean): Boolean = javaConstructorIsCreatorAnnotated.get(key)
?: calc(key).let { javaConstructorIsCreatorAnnotated.putIfAbsent(key, it) ?: it }

MODIFY
src/main/kotlin/com/fasterxml/jackson/module/kotlin/ValueCreator.kt
src/main/kotlin/com/fasterxml/jackson/module/kotlin/ValueCreator.kt
@@ -2,11 +2,6 @@ package com.fasterxml.jackson.module.kotlin
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.MapperFeature
-import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
-import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
-import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams
-import java.lang.reflect.Constructor
-import java.lang.reflect.Method
import kotlin.reflect.KFunction
import kotlin.reflect.KParameter
import kotlin.reflect.full.valueParameters
@@ -48,17 +43,4 @@ internal sealed class ValueCreator<T> {
* Function call with default values enabled.
*/
fun callBy(args: Map<KParameter, Any?>): T = callable.callBy(args)
-
- companion object {
- @Suppress("UNCHECKED_CAST")
- fun of(
- _withArgsCreator: AnnotatedWithParams, cache: ReflectionCache
- ): ValueCreator<*>? = when (_withArgsCreator) {
- is AnnotatedConstructor -> cache.kotlinFromJava(_withArgsCreator.annotated as Constructor<Any>)
- ?.let { ConstructorValueCreator(it) }
- is AnnotatedMethod -> cache.kotlinFromJava(_withArgsCreator.annotated as Method)
- ?.let { MethodValueCreator.of(it) }
- else -> throw IllegalStateException("Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator.annotated.javaClass.name}")
- } // we cannot reflect this method so do the default Java-ish behavior
- }
}

fix to use cache