@@ -14,12 +14,13 @@ import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector
14
14
import com.fasterxml.jackson.databind.util.BeanUtil
15
15
import java.lang.reflect.Constructor
16
16
import java.lang.reflect.Method
17
- import java.util.*
17
+ import java.util.Locale
18
18
import kotlin.reflect.KClass
19
19
import kotlin.reflect.KFunction
20
20
import kotlin.reflect.KParameter
21
21
import kotlin.reflect.full.companionObject
22
22
import kotlin.reflect.full.declaredFunctions
23
+ import kotlin.reflect.full.hasAnnotation
23
24
import kotlin.reflect.full.memberProperties
24
25
import kotlin.reflect.full.primaryConstructor
25
26
import kotlin.reflect.jvm.internal.KotlinReflectionInternalError
@@ -59,68 +60,44 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c
59
60
}
60
61
61
62
@Suppress(" UNCHECKED_CAST" )
62
- override fun hasCreatorAnnotation (member : Annotated ): Boolean {
63
+ private fun hasCreatorAnnotation (member : AnnotatedConstructor ): Boolean {
63
64
// don't add a JsonCreator to any constructor if one is declared already
64
65
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
71
69
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) }
75
73
76
- val propertyNames = kClass.memberProperties.map { it.name }.toSet()
74
+ val propertyNames = kClass.memberProperties.map { it.name }.toSet()
77
75
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 >() }
85
84
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
89
89
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)
119
91
}
120
92
}
121
- return false
122
93
}
123
94
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
+
124
101
@Suppress(" UNCHECKED_CAST" )
125
102
private fun findKotlinParameterName (param : AnnotatedParameter ): String? {
126
103
return if (param.declaringClass.isKotlinClass()) {
@@ -165,3 +142,19 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c
165
142
ReplaceWith (" with(receiver) { declaringClass.declaredMethods.any { it.name.contains('-') } }" )
166
143
)
167
144
private 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