diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index ca9d0d67..30a045ad 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -18,6 +18,7 @@ Contributors: # 2.17.0 (not yet released) WrongWrong (@k163377) +* #740: Reduce conversion cache from Executable to KFunction. * #738: Fix JacksonInject priority. * #732: SequenceSerializer removed. * #727: Fixed overriding findCreatorAnnotation instead of hasCreatorAnnotation diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 628d8be7..245c49ea 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -18,6 +18,8 @@ Co-maintainers: 2.17.0 (not yet released) +#740: Reduce conversion cache from Executable to KFunction. + This will reduce memory usage efficiency and total memory consumption, but may result in a minor performance degradation in use cases where a large number of factory functions are used as JsonCreator. #738: JacksonInject is now preferred over the default argument(fixes #722). #732: SequenceSerializer removed. #727: Fixed overriding findCreatorAnnotation instead of hasCreatorAnnotation. diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt index bd61b979..7af632b4 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt @@ -95,9 +95,8 @@ internal class KotlinAnnotationIntrospector( if (!useJavaDurationConversion) return null return (a as? AnnotatedParameter)?.let { param -> - @Suppress("UNCHECKED_CAST") val function: KFunction<*> = when (val owner = param.owner.member) { - is Constructor<*> -> cache.kotlinFromJava(owner as Constructor) + is Constructor<*> -> cache.kotlinFromJava(owner) is Method -> cache.kotlinFromJava(owner) else -> null } ?: return@let null diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index babe8e92..d4af91b9 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -79,13 +79,12 @@ internal class KotlinNamesAnnotationIntrospector( } } - @Suppress("UNCHECKED_CAST") private fun hasCreatorAnnotation(member: AnnotatedConstructor): Boolean { // don't add a JsonCreator to any constructor if one is declared already val kClass = member.declaringClass.kotlin .apply { if (this in ignoredClassesForImplyingJsonCreator) return false } - val kConstructor = cache.kotlinFromJava(member.annotated as Constructor) ?: return false + val kConstructor = cache.kotlinFromJava(member.annotated) ?: return false // TODO: should we do this check or not? It could cause failures if we miss another way a property could be set // val requiredProperties = kClass.declaredMemberProperties.filter {!it.returnType.isMarkedNullable }.map { it.name }.toSet() diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt index dbcb6b17..eef3e61b 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/ReflectionCache.kt @@ -19,7 +19,7 @@ import kotlin.reflect.jvm.kotlinFunction internal class ReflectionCache(reflectionCacheSize: Int) : Serializable { companion object { // Increment is required when properties that use LRUMap are changed. - private const val serialVersionUID = 1L + private const val serialVersionUID = 2L } sealed class BooleanTriState(val value: Boolean?) { @@ -42,8 +42,7 @@ internal class ReflectionCache(reflectionCacheSize: Int) : Serializable { } } - private val javaConstructorToKotlin = LRUMap, KFunction>(reflectionCacheSize, reflectionCacheSize) - private val javaMethodToKotlin = LRUMap>(reflectionCacheSize, reflectionCacheSize) + private val javaExecutableToKotlin = LRUMap>(reflectionCacheSize, reflectionCacheSize) private val javaExecutableToValueCreator = LRUMap>(reflectionCacheSize, reflectionCacheSize) private val javaConstructorIsCreatorAnnotated = LRUMap(reflectionCacheSize, reflectionCacheSize) private val javaMemberIsRequired = LRUMap(reflectionCacheSize, reflectionCacheSize) @@ -57,11 +56,11 @@ internal class ReflectionCache(reflectionCacheSize: Int) : Serializable { private val valueClassBoxConverterCache: LRUMap, ValueClassBoxConverter<*, *>> = LRUMap(0, reflectionCacheSize) - fun kotlinFromJava(key: Constructor): KFunction? = javaConstructorToKotlin.get(key) - ?: key.kotlinFunction?.let { javaConstructorToKotlin.putIfAbsent(key, it) ?: it } + fun kotlinFromJava(key: Constructor<*>): KFunction<*>? = javaExecutableToKotlin.get(key) + ?: key.kotlinFunction?.let { javaExecutableToKotlin.putIfAbsent(key, it) ?: it } - fun kotlinFromJava(key: Method): KFunction<*>? = javaMethodToKotlin.get(key) - ?: key.kotlinFunction?.let { javaMethodToKotlin.putIfAbsent(key, it) ?: it } + fun kotlinFromJava(key: Method): KFunction<*>? = javaExecutableToKotlin.get(key) + ?: key.kotlinFunction?.let { javaExecutableToKotlin.putIfAbsent(key, it) ?: it } /** * return null if...