Skip to content

Commit

Permalink
Merge remote-tracking branch 'FasterXML/2.17'
Browse files Browse the repository at this point in the history
  • Loading branch information
k163377 committed Dec 10, 2023
2 parents b2d77c3 + 6883c16 commit 7112c02
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 11 deletions.
1 change: 1 addition & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,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<Any>)
is Constructor<*> -> cache.kotlinFromJava(owner)
is Method -> cache.kotlinFromJava(owner)
else -> null
} ?: return@let null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Any>) ?: 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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ internal class KotlinValueInstantiator(
paramDef.isOptional -> return@forEachIndexed
// do not try to create any object if it is nullable and the value is missing
paramType.isMarkedNullable -> null
// Primitive types always try to get from a buffer, considering several settings
jsonProp.type.isPrimitive -> buffer.getParameter(jsonProp)
// to get suitable "missing" value provided by deserializer
else -> jsonProp.valueDeserializer?.getAbsentValue(ctxt)
}
Expand Down
13 changes: 6 additions & 7 deletions src/main/kotlin/tools/jackson/module/kotlin/ReflectionCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,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?) {
Expand All @@ -43,8 +43,7 @@ internal class ReflectionCache(reflectionCacheSize: Int) : Serializable {
}
}

private val javaConstructorToKotlin = SimpleLookupCache<Constructor<Any>, KFunction<Any>>(reflectionCacheSize, reflectionCacheSize)
private val javaMethodToKotlin = SimpleLookupCache<Method, KFunction<*>>(reflectionCacheSize, reflectionCacheSize)
private val javaExecutableToKotlin = SimpleLookupCache<Executable, KFunction<*>>(reflectionCacheSize, reflectionCacheSize)
private val javaExecutableToValueCreator = SimpleLookupCache<Executable, ValueCreator<*>>(reflectionCacheSize, reflectionCacheSize)
private val javaConstructorIsCreatorAnnotated = SimpleLookupCache<AnnotatedConstructor, Boolean>(reflectionCacheSize, reflectionCacheSize)
private val javaMemberIsRequired = SimpleLookupCache<AnnotatedMember, BooleanTriState?>(reflectionCacheSize, reflectionCacheSize)
Expand All @@ -58,11 +57,11 @@ internal class ReflectionCache(reflectionCacheSize: Int) : Serializable {
private val valueClassBoxConverterCache: SimpleLookupCache<KClass<*>, ValueClassBoxConverter<*, *>> =
SimpleLookupCache(0, reflectionCacheSize)

fun kotlinFromJava(key: Constructor<Any>): KFunction<Any>? = 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...
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tools.jackson.module.kotlin.test.github

import com.fasterxml.jackson.annotation.JsonSetter
import com.fasterxml.jackson.annotation.Nulls
import org.junit.Assert.assertThrows
import org.junit.Test
import tools.jackson.databind.exc.MismatchedInputException
import tools.jackson.module.kotlin.jacksonObjectMapper
import tools.jackson.module.kotlin.readValue

class Github738 {
data class D(@JsonSetter(nulls = Nulls.FAIL) val v: Int)

@Test
fun test() {
val mapper = jacksonObjectMapper()
// nulls = FAIL is reflected if it is primitive and missing
assertThrows(MismatchedInputException::class.java) { mapper.readValue<D>("{}") }
}
}

0 comments on commit 7112c02

Please sign in to comment.