@@ -14,12 +14,13 @@ import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector
1414import com.fasterxml.jackson.databind.util.BeanUtil
1515import java.lang.reflect.Constructor
1616import java.lang.reflect.Method
17- import java.util.*
17+ import java.util.Locale
1818import kotlin.reflect.KClass
1919import kotlin.reflect.KFunction
2020import kotlin.reflect.KParameter
2121import kotlin.reflect.full.companionObject
2222import kotlin.reflect.full.declaredFunctions
23+ import kotlin.reflect.full.hasAnnotation
2324import kotlin.reflect.full.memberProperties
2425import kotlin.reflect.full.primaryConstructor
2526import kotlin.reflect.jvm.internal.KotlinReflectionInternalError
@@ -59,68 +60,44 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c
5960 }
6061
6162 @Suppress(" UNCHECKED_CAST" )
62- override fun hasCreatorAnnotation (member : Annotated ): Boolean {
63+ private fun hasCreatorAnnotation (member : AnnotatedConstructor ): Boolean {
6364 // don't add a JsonCreator to any constructor if one is declared already
6465
65- if (member is AnnotatedConstructor && ! member.declaringClass.isEnum) {
66- // if has parameters, is a Kotlin class, and the parameters all have parameter annotations, then pretend we have a JsonCreator
67- if (member.parameterCount > 0 && member.declaringClass.isKotlinClass()) {
68- return cache.checkConstructorIsCreatorAnnotated(member) {
69- val kClass = cache.kotlinFromJava(member.declaringClass as Class <Any >)
70- val kConstructor = cache.kotlinFromJava(member.annotated as Constructor <Any >)
66+ val kClass = cache.kotlinFromJava(member.declaringClass as Class <Any >)
67+ .apply { if (this in ignoredClassesForImplyingJsonCreator) return false }
68+ val kConstructor = cache.kotlinFromJava(member.annotated as Constructor <Any >) ? : return false
7169
72- if (kConstructor != null ) {
73- val isPrimaryConstructor = kClass.primaryConstructor == kConstructor ||
74- (kClass.primaryConstructor == null && kClass.constructors.size == 1 )
70+ // TODO: should we do this check or not? It could cause failures if we miss another way a property could be set
71+ // val requiredProperties = kClass.declaredMemberProperties.filter {!it.returnType.isMarkedNullable }.map { it.name }.toSet()
72+ // val areAllRequiredParametersInConstructor = kConstructor.parameters.all { requiredProperties.contains(it.name) }
7573
76- val propertyNames = kClass.memberProperties.map { it.name }.toSet()
74+ val propertyNames = kClass.memberProperties.map { it.name }.toSet()
7775
78- fun KFunction <* >.isPossibleSingleString (): Boolean {
79- val result = parameters.size == 1 &&
80- parameters[0 ].name !in propertyNames &&
81- parameters[0 ].type.javaType == String ::class .java &&
82- parameters[0 ].annotations.none { it.annotationClass.java == JsonProperty ::class .java }
83- return result
84- }
76+ return when {
77+ kConstructor.isPossibleSingleString(propertyNames) -> false
78+ kConstructor.parameters.any { it.name == null } -> false
79+ ! kClass.isPrimaryConstructor(kConstructor) -> false
80+ else -> {
81+ val anyConstructorHasJsonCreator = kClass.constructors
82+ .filterOutSingleStringCallables(propertyNames)
83+ .any { it.hasAnnotation<JsonCreator >() }
8584
86- fun Collection <KFunction <* >>.filterOutSingleStringCallables (): Collection <KFunction <* >> {
87- return this .filter { ! it.isPossibleSingleString() }
88- }
85+ val anyCompanionMethodIsJsonCreator = member.type.rawClass.kotlin.companionObject?.declaredFunctions
86+ ?.filterOutSingleStringCallables(propertyNames)
87+ ?.any { it.hasAnnotation<JsonCreator >() && it.hasAnnotation<JvmStatic >() }
88+ ? : false
8989
90- val anyConstructorHasJsonCreator = kClass.constructors.filterOutSingleStringCallables()
91- .any { it.annotations.any { it.annotationClass.java == JsonCreator ::class .java }
92- }
93-
94- val anyCompanionMethodIsJsonCreator = member.type.rawClass.kotlin.companionObject?.declaredFunctions
95- ?.filterOutSingleStringCallables()?.any {
96- it.annotations.any { it.annotationClass.java == JvmStatic ::class .java } &&
97- it.annotations.any { it.annotationClass.java == JsonCreator ::class .java }
98- } ? : false
99-
100- // TODO: should we do this check or not? It could cause failures if we miss another way a property could be set
101- // val requiredProperties = kClass.declaredMemberProperties.filter {!it.returnType.isMarkedNullable }.map { it.name }.toSet()
102- // val areAllRequiredParametersInConstructor = kConstructor.parameters.all { requiredProperties.contains(it.name) }
103-
104- val areAllParametersValid = kConstructor.parameters.size == kConstructor.parameters.count { it.name != null }
105-
106- val isSingleStringConstructor = kConstructor.isPossibleSingleString()
107-
108- val implyCreatorAnnotation = isPrimaryConstructor
109- && ! (anyConstructorHasJsonCreator || anyCompanionMethodIsJsonCreator)
110- && areAllParametersValid
111- && ! isSingleStringConstructor
112- && kClass !in ignoredClassesForImplyingJsonCreator
113-
114- implyCreatorAnnotation
115- } else {
116- false
117- }
118- }
90+ ! (anyConstructorHasJsonCreator || anyCompanionMethodIsJsonCreator)
11991 }
12092 }
121- return false
12293 }
12394
95+ override fun hasCreatorAnnotation (member : Annotated ): Boolean =
96+ if (member is AnnotatedConstructor && member.isKotlinConstructorWithParameters())
97+ cache.checkConstructorIsCreatorAnnotated(member) { hasCreatorAnnotation(it) }
98+ else
99+ false
100+
124101 @Suppress(" UNCHECKED_CAST" )
125102 private fun findKotlinParameterName (param : AnnotatedParameter ): String? {
126103 return if (param.declaringClass.isKotlinClass()) {
@@ -165,3 +142,19 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c
165142 ReplaceWith (" with(receiver) { declaringClass.declaredMethods.any { it.name.contains('-') } }" )
166143)
167144private fun AnnotatedMethod.isInlineClass () = declaringClass.declaredMethods.any { it.name.contains(' -' ) }
145+
146+ // if has parameters, is a Kotlin class, and the parameters all have parameter annotations, then pretend we have a JsonCreator
147+ private fun AnnotatedConstructor.isKotlinConstructorWithParameters (): Boolean =
148+ parameterCount > 0 && declaringClass.isKotlinClass() && ! declaringClass.isEnum
149+
150+ private fun KFunction <* >.isPossibleSingleString (propertyNames : Set <String >): Boolean = parameters.size == 1 &&
151+ parameters[0 ].name !in propertyNames &&
152+ parameters[0 ].type.javaType == String ::class .java &&
153+ ! parameters[0 ].hasAnnotation<JsonProperty >()
154+
155+ private fun Collection <KFunction <* >>.filterOutSingleStringCallables (propertyNames : Set <String >): Collection <KFunction <* >> =
156+ this .filter { ! it.isPossibleSingleString(propertyNames) }
157+
158+ private fun KClass <* >.isPrimaryConstructor (kConstructor : KFunction <* >) = this .primaryConstructor.let {
159+ it == kConstructor || (it == null && this .constructors.size == 1 )
160+ }
0 commit comments