@@ -8,7 +8,6 @@ import com.fasterxml.jackson.databind.Module
8
8
import com.fasterxml.jackson.databind.cfg.MapperConfig
9
9
import com.fasterxml.jackson.databind.introspect.*
10
10
import com.fasterxml.jackson.databind.jsontype.NamedType
11
- import com.fasterxml.jackson.databind.ser.std.StdSerializer
12
11
import com.fasterxml.jackson.databind.util.Converter
13
12
import java.lang.reflect.AccessibleObject
14
13
import java.lang.reflect.Constructor
@@ -22,14 +21,19 @@ import kotlin.reflect.KType
22
21
import kotlin.reflect.full.createType
23
22
import kotlin.reflect.full.declaredMemberProperties
24
23
import kotlin.reflect.full.memberProperties
24
+ import kotlin.reflect.full.valueParameters
25
25
import kotlin.reflect.jvm.*
26
+ import kotlin.time.Duration
26
27
27
28
28
- internal class KotlinAnnotationIntrospector (private val context : Module .SetupContext ,
29
- private val cache : ReflectionCache ,
30
- private val nullToEmptyCollection : Boolean ,
31
- private val nullToEmptyMap : Boolean ,
32
- private val nullIsSameAsDefault : Boolean ) : NopAnnotationIntrospector() {
29
+ internal class KotlinAnnotationIntrospector (
30
+ private val context : Module .SetupContext ,
31
+ private val cache : ReflectionCache ,
32
+ private val nullToEmptyCollection : Boolean ,
33
+ private val nullToEmptyMap : Boolean ,
34
+ private val nullIsSameAsDefault : Boolean ,
35
+ private val useJavaDurationConversion : Boolean ,
36
+ ) : NopAnnotationIntrospector() {
33
37
34
38
// TODO: implement nullIsSameAsDefault flag, which represents when TRUE that if something has a default value, it can be passed a null to default it
35
39
// this likely impacts this class to be accurate about what COULD be considered required
@@ -66,11 +70,23 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
66
70
67
71
override fun findSerializationConverter (a : Annotated ): Converter <* , * >? = when (a) {
68
72
// Find a converter to handle the case where the getter returns an unboxed value from the value class.
69
- is AnnotatedMethod -> cache.findValueClassReturnType(a)
70
- ?.let { cache.getValueClassBoxConverter(a.rawReturnType, it) }
71
- is AnnotatedClass -> a
72
- .takeIf { Sequence ::class .java.isAssignableFrom(it.rawType) }
73
- ?.let { SequenceToIteratorConverter (it.type) }
73
+ is AnnotatedMethod -> a.findValueClassReturnType()?.let {
74
+ if (useJavaDurationConversion && it == Duration ::class ) {
75
+ if (a.rawReturnType == Duration ::class .java)
76
+ KotlinToJavaDurationConverter
77
+ else
78
+ KotlinDurationValueToJavaDurationConverter
79
+ } else {
80
+ cache.getValueClassBoxConverter(a.rawReturnType, it)
81
+ }
82
+ }
83
+ is AnnotatedClass -> lookupKotlinTypeConverter(a)
84
+ else -> null
85
+ }
86
+
87
+ private fun lookupKotlinTypeConverter (a : AnnotatedClass ) = when {
88
+ Sequence ::class .java.isAssignableFrom(a.rawType) -> SequenceToIteratorConverter (a.type)
89
+ Duration ::class .java == a.rawType -> KotlinToJavaDurationConverter .takeIf { useJavaDurationConversion }
74
90
else -> null
75
91
}
76
92
@@ -81,10 +97,29 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
81
97
82
98
// Perform proper serialization even if the value wrapped by the value class is null.
83
99
// If value is a non-null object type, it must not be reboxing.
84
- override fun findNullSerializer (am : Annotated ): JsonSerializer <* >? = (am as ? AnnotatedMethod )?.let { _ ->
85
- cache.findValueClassReturnType(am)
86
- ?.takeIf { it.requireRebox() }
87
- ?.let { cache.getValueClassBoxConverter(am.rawReturnType, it).delegatingSerializer }
100
+ override fun findNullSerializer (am : Annotated ): JsonSerializer <* >? = (am as ? AnnotatedMethod )
101
+ ?.findValueClassReturnType()
102
+ ?.takeIf { it.requireRebox() }
103
+ ?.let { cache.getValueClassBoxConverter(am.rawReturnType, it).delegatingSerializer }
104
+
105
+ override fun findDeserializationConverter (a : Annotated ): Any? {
106
+ if (! useJavaDurationConversion) return null
107
+
108
+ return (a as ? AnnotatedParameter )?.let { param ->
109
+ @Suppress(" UNCHECKED_CAST" )
110
+ val function: KFunction <* > = when (val owner = param.owner.member) {
111
+ is Constructor <* > -> cache.kotlinFromJava(owner as Constructor <Any >)
112
+ is Method -> cache.kotlinFromJava(owner)
113
+ else -> null
114
+ } ? : return @let null
115
+ val valueParameter = function.valueParameters[a.index]
116
+
117
+ if (valueParameter.type.classifier == Duration ::class ) {
118
+ JavaToKotlinDurationConverter
119
+ } else {
120
+ null
121
+ }
122
+ }
88
123
}
89
124
90
125
/* *
@@ -102,7 +137,7 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
102
137
103
138
private fun AnnotatedField.hasRequiredMarker (): Boolean? {
104
139
val byAnnotation = (member as Field ).isRequiredByAnnotation()
105
- val byNullability = (member as Field ).kotlinProperty?.returnType?.isRequired()
140
+ val byNullability = (member as Field ).kotlinProperty?.returnType?.isRequired()
106
141
107
142
return requiredAnnotationOrNullability(byAnnotation, byNullability)
108
143
}
@@ -122,7 +157,7 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
122
157
}
123
158
124
159
private fun Method.isRequiredByAnnotation (): Boolean? {
125
- return (this .annotations.firstOrNull { it.annotationClass.java == JsonProperty ::class .java } as ? JsonProperty )?.required
160
+ return (this .annotations.firstOrNull { it.annotationClass.java == JsonProperty ::class .java } as ? JsonProperty )?.required
126
161
}
127
162
128
163
// Since Kotlin's property has the same Type for each field, getter, and setter,
@@ -171,12 +206,14 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
171
206
return requiredAnnotationOrNullability(byAnnotation, byNullability)
172
207
}
173
208
209
+ private fun AnnotatedMethod.findValueClassReturnType () = cache.findValueClassReturnType(this )
210
+
174
211
private fun KFunction <* >.isConstructorParameterRequired (index : Int ): Boolean {
175
212
return isParameterRequired(index)
176
213
}
177
214
178
215
private fun KFunction <* >.isMethodParameterRequired (index : Int ): Boolean {
179
- return isParameterRequired(index+ 1 )
216
+ return isParameterRequired(index + 1 )
180
217
}
181
218
182
219
private fun KFunction <* >.isParameterRequired (index : Int ): Boolean {
0 commit comments