@@ -5,11 +5,13 @@ import com.fasterxml.jackson.annotation.JsonProperty
5
5
import com.fasterxml.jackson.databind.JavaType
6
6
import com.fasterxml.jackson.databind.cfg.MapperConfig
7
7
import com.fasterxml.jackson.databind.introspect.Annotated
8
+ import com.fasterxml.jackson.databind.introspect.AnnotatedClass
8
9
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor
9
10
import com.fasterxml.jackson.databind.introspect.AnnotatedMember
10
11
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
11
12
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter
12
13
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector
14
+ import com.fasterxml.jackson.databind.introspect.PotentialCreator
13
15
import java.util.Locale
14
16
import kotlin.reflect.KClass
15
17
import kotlin.reflect.KFunction
@@ -18,6 +20,7 @@ import kotlin.reflect.full.declaredFunctions
18
20
import kotlin.reflect.full.hasAnnotation
19
21
import kotlin.reflect.full.memberProperties
20
22
import kotlin.reflect.full.primaryConstructor
23
+ import kotlin.reflect.jvm.javaConstructor
21
24
import kotlin.reflect.jvm.javaGetter
22
25
import kotlin.reflect.jvm.javaType
23
26
@@ -84,62 +87,40 @@ internal class KotlinNamesAnnotationIntrospector(
84
87
}
85
88
} ? : baseType
86
89
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) }
90
+ override fun findDefaultCreator (
91
+ config : MapperConfig <* >,
92
+ valueClass : AnnotatedClass ,
93
+ declaredConstructors : List <PotentialCreator >,
94
+ declaredFactories : List <PotentialCreator >
95
+ ): PotentialCreator ? {
96
+ val kClass = valueClass.creatableKotlinClass() ? : return null
96
97
97
98
val propertyNames = kClass.memberProperties.map { it.name }.toSet()
98
99
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
- }
100
+ val defaultCreator = kClass.let { _ ->
101
+ // By default, the primary constructor or the only publicly available constructor may be used
102
+ val ctor = kClass.primaryConstructor ? : kClass.constructors.takeIf { it.size == 1 }?.single()
103
+ ctor?.takeIf { it.isPossibleCreator(propertyNames) }
115
104
}
116
- }
117
-
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
105
+ ?.javaConstructor
106
+ ? : return null
122
107
123
- return JsonCreator .Mode .DEFAULT .takeIf {
124
- cache.checkConstructorIsCreatorAnnotated(ann) { hasCreatorAnnotation(it) }
125
- }
108
+ return declaredConstructors.find { it.creator().annotated == defaultCreator }
126
109
}
127
110
128
111
private fun findKotlinParameterName (param : AnnotatedParameter ): String? = cache.findKotlinParameter(param)?.name
129
112
}
130
113
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 >()
114
+ // If it is not a Kotlin class or an Enum, Creator is not used
115
+ private fun AnnotatedClass.creatableKotlinClass (): KClass <* >? = annotated
116
+ .takeIf { it.isKotlinClass() && ! it.isEnum }
117
+ ?.kotlin
139
118
140
- private fun Collection <KFunction <* >>.filterOutSingleStringCallables (propertyNames : Set <String >): Collection <KFunction <* >> =
141
- this .filter { ! it.isPossibleSingleString(propertyNames) }
119
+ private fun KFunction <* >.isPossibleCreator (propertyNames : Set <String >): Boolean = 0 < parameters.size
120
+ && ! isPossibleSingleString(propertyNames)
121
+ && parameters.none { it.name == null }
142
122
143
- private fun KClass <* >.isPrimaryConstructor (kConstructor : KFunction <* >) = this .primaryConstructor.let {
144
- it == kConstructor || (it == null && this .constructors.size == 1 )
145
- }
123
+ private fun KFunction <* >.isPossibleSingleString (propertyNames : Set <String >): Boolean = parameters.size == 1 &&
124
+ parameters[0 ].name !in propertyNames &&
125
+ parameters[0 ].type.javaType == String ::class .java &&
126
+ ! parameters[0 ].hasAnnotation<JsonProperty >()
0 commit comments