@@ -5,11 +5,14 @@ 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
15
+ import java.lang.reflect.Constructor
13
16
import java.util.Locale
14
17
import kotlin.reflect.KClass
15
18
import kotlin.reflect.KFunction
@@ -18,6 +21,7 @@ import kotlin.reflect.full.declaredFunctions
18
21
import kotlin.reflect.full.hasAnnotation
19
22
import kotlin.reflect.full.memberProperties
20
23
import kotlin.reflect.full.primaryConstructor
24
+ import kotlin.reflect.jvm.javaConstructor
21
25
import kotlin.reflect.jvm.javaGetter
22
26
import kotlin.reflect.jvm.javaType
23
27
@@ -84,62 +88,43 @@ internal class KotlinNamesAnnotationIntrospector(
84
88
}
85
89
} ? : baseType
86
90
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
96
98
97
99
val propertyNames = kClass.memberProperties.map { it.name }.toSet()
98
100
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) }
115
105
}
116
- }
106
+ ? : return null
117
107
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
125
112
}
126
113
}
127
114
128
115
private fun findKotlinParameterName (param : AnnotatedParameter ): String? = cache.findKotlinParameter(param)?.name
129
116
}
130
117
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
139
122
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 }
142
126
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