@@ -5,11 +5,14 @@ import com.fasterxml.jackson.annotation.JsonProperty
55import com.fasterxml.jackson.databind.JavaType
66import com.fasterxml.jackson.databind.cfg.MapperConfig
77import com.fasterxml.jackson.databind.introspect.Annotated
8+ import com.fasterxml.jackson.databind.introspect.AnnotatedClass
89import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
910import com.fasterxml.jackson.databind.introspect.AnnotatedMember
1011import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
1112import com.fasterxml.jackson.databind.introspect.AnnotatedParameter
1213import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector
14+ import com.fasterxml.jackson.databind.introspect.PotentialCreator
15+ import java.lang.reflect.Constructor
1316import java.util.Locale
1417import kotlin.reflect.KClass
1518import kotlin.reflect.KFunction
@@ -18,6 +21,7 @@ import kotlin.reflect.full.declaredFunctions
1821import kotlin.reflect.full.hasAnnotation
1922import kotlin.reflect.full.memberProperties
2023import kotlin.reflect.full.primaryConstructor
24+ import kotlin.reflect.jvm.javaConstructor
2125import kotlin.reflect.jvm.javaGetter
2226import kotlin.reflect.jvm.javaType
2327
@@ -84,62 +88,43 @@ internal class KotlinNamesAnnotationIntrospector(
8488 }
8589 } ? : baseType
8690
87- private fun hasCreatorAnnotation (member : AnnotatedConstructor ): Boolean {
88- // don't add a JsonCreator to any constructor if one is declared already
89-
90- val kClass = member.declaringClass.kotlin
91- val kConstructor = cache.kotlinFromJava(member.annotated) ? : return false
92-
93- // TODO: should we do this check or not? It could cause failures if we miss another way a property could be set
94- // val requiredProperties = kClass.declaredMemberProperties.filter {!it.returnType.isMarkedNullable }.map { it.name }.toSet()
95- // val areAllRequiredParametersInConstructor = kConstructor.parameters.all { requiredProperties.contains(it.name) }
91+ override fun findDefaultCreator (
92+ config : MapperConfig <* >,
93+ valueClass : AnnotatedClass ,
94+ declaredConstructors : List <PotentialCreator >,
95+ declaredFactories : List <PotentialCreator >
96+ ): PotentialCreator ? {
97+ val kClass = valueClass.creatableKotlinClass() ? : return null
9698
9799 val propertyNames = kClass.memberProperties.map { it.name }.toSet()
98100
99- return when {
100- kConstructor.isPossibleSingleString(propertyNames) -> false
101- kConstructor.parameters.any { it.name == null } -> false
102- ! kClass.isPrimaryConstructor(kConstructor) -> false
103- else -> {
104- val anyConstructorHasJsonCreator = kClass.constructors
105- .filterOutSingleStringCallables(propertyNames)
106- .any { it.hasAnnotation<JsonCreator >() }
107-
108- val anyCompanionMethodIsJsonCreator = member.type.rawClass.kotlin.companionObject?.declaredFunctions
109- ?.filterOutSingleStringCallables(propertyNames)
110- ?.any { it.hasAnnotation<JsonCreator >() && it.hasAnnotation<JvmStatic >() }
111- ? : false
112-
113- ! (anyConstructorHasJsonCreator || anyCompanionMethodIsJsonCreator)
114- }
101+ val defaultCreator = kClass.let { _ ->
102+ // By default, the primary constructor or the only publicly available constructor may be used
103+ val ctor = kClass.primaryConstructor ? : kClass.constructors.takeIf { it.size == 1 }?.single()
104+ ctor?.takeIf { it.isPossibleCreator(propertyNames) }
115105 }
116- }
106+ ? : return null
117107
118- // TODO: possible work around for JsonValue class that requires the class constructor to have the JsonCreator(DELEGATED) set?
119- // since we infer the creator at times for these methods, the wrong mode could be implied.
120- override fun findCreatorAnnotation (config : MapperConfig <* >, ann : Annotated ): JsonCreator .Mode ? {
121- if (ann !is AnnotatedConstructor || ! ann.isKotlinConstructorWithParameters()) return null
122-
123- return JsonCreator .Mode .DEFAULT .takeIf {
124- cache.checkConstructorIsCreatorAnnotated(ann) { hasCreatorAnnotation(it) }
108+ return declaredConstructors.find {
109+ // To avoid problems with constructors that include `value class` as an argument,
110+ // convert to `KFunction` and compare
111+ cache.kotlinFromJava(it.creator().annotated as Constructor <* >) == defaultCreator
125112 }
126113 }
127114
128115 private fun findKotlinParameterName (param : AnnotatedParameter ): String? = cache.findKotlinParameter(param)?.name
129116}
130117
131- // if has parameters, is a Kotlin class, and the parameters all have parameter annotations, then pretend we have a JsonCreator
132- private fun AnnotatedConstructor.isKotlinConstructorWithParameters (): Boolean =
133- parameterCount > 0 && declaringClass.isKotlinClass() && ! declaringClass.isEnum
134-
135- private fun KFunction <* >.isPossibleSingleString (propertyNames : Set <String >): Boolean = parameters.size == 1 &&
136- parameters[0 ].name !in propertyNames &&
137- parameters[0 ].type.javaType == String ::class .java &&
138- ! parameters[0 ].hasAnnotation<JsonProperty >()
118+ // If it is not a Kotlin class or an Enum, Creator is not used
119+ private fun AnnotatedClass.creatableKotlinClass (): KClass <* >? = annotated
120+ .takeIf { it.isKotlinClass() && ! it.isEnum }
121+ ?.kotlin
139122
140- private fun Collection <KFunction <* >>.filterOutSingleStringCallables (propertyNames : Set <String >): Collection <KFunction <* >> =
141- this .filter { ! it.isPossibleSingleString(propertyNames) }
123+ private fun KFunction <* >.isPossibleCreator (propertyNames : Set <String >): Boolean = 0 < parameters.size
124+ && ! isPossibleSingleString(propertyNames)
125+ && parameters.none { it.name == null }
142126
143- private fun KClass <* >.isPrimaryConstructor (kConstructor : KFunction <* >) = this .primaryConstructor.let {
144- it == kConstructor || (it == null && this .constructors.size == 1 )
145- }
127+ private fun KFunction <* >.isPossibleSingleString (propertyNames : Set <String >): Boolean = parameters.size == 1 &&
128+ parameters[0 ].name !in propertyNames &&
129+ parameters[0 ].type.javaType == String ::class .java &&
130+ ! parameters[0 ].hasAnnotation<JsonProperty >()
0 commit comments