@@ -3,6 +3,7 @@ package com.fasterxml.jackson.module.kotlin
3
3
import com.fasterxml.jackson.databind.BeanDescription
4
4
import com.fasterxml.jackson.databind.DeserializationConfig
5
5
import com.fasterxml.jackson.databind.DeserializationContext
6
+ import com.fasterxml.jackson.databind.JavaType
6
7
import com.fasterxml.jackson.databind.deser.SettableBeanProperty
7
8
import com.fasterxml.jackson.databind.deser.ValueInstantiator
8
9
import com.fasterxml.jackson.databind.deser.ValueInstantiators
@@ -13,6 +14,7 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException
13
14
import java.lang.reflect.TypeVariable
14
15
import kotlin.reflect.KParameter
15
16
import kotlin.reflect.KType
17
+ import kotlin.reflect.KTypeProjection
16
18
import kotlin.reflect.jvm.javaType
17
19
18
20
internal class KotlinValueInstantiator (
@@ -23,6 +25,13 @@ internal class KotlinValueInstantiator(
23
25
private val nullIsSameAsDefault : Boolean ,
24
26
private val strictNullChecks : Boolean
25
27
) : StdValueInstantiator(src) {
28
+ private fun JavaType.requireEmptyValue () =
29
+ (nullToEmptyCollection && this .isCollectionLikeType) || (nullToEmptyMap && this .isMapLikeType)
30
+
31
+ private fun KType.isGenericTypeVar () = javaType is TypeVariable <* >
32
+
33
+ private fun List<KTypeProjection>.markedNonNullAt (index : Int ) = getOrNull(index)?.type?.isMarkedNullable == false
34
+
26
35
override fun createFromObjectWith (
27
36
ctxt : DeserializationContext ,
28
37
props : Array <out SettableBeanProperty >,
@@ -58,14 +67,15 @@ internal class KotlinValueInstantiator(
58
67
return @forEachIndexed
59
68
}
60
69
70
+ val paramType = paramDef.type
61
71
var paramVal = if (! isMissing || paramDef.isPrimitive() || jsonProp.hasInjectableValueId()) {
62
72
val tempParamVal = buffer.getParameter(jsonProp)
63
73
if (nullIsSameAsDefault && tempParamVal == null && paramDef.isOptional) {
64
74
return @forEachIndexed
65
75
}
66
76
tempParamVal
67
77
} else {
68
- if (paramDef.type .isMarkedNullable) {
78
+ if (paramType .isMarkedNullable) {
69
79
// do not try to create any object if it is nullable and the value is missing
70
80
null
71
81
} else {
@@ -74,46 +84,51 @@ internal class KotlinValueInstantiator(
74
84
}
75
85
}
76
86
77
- if (paramVal == null && ((nullToEmptyCollection && jsonProp.type.isCollectionLikeType) || (nullToEmptyMap && jsonProp.type.isMapLikeType))) {
78
- paramVal = NullsAsEmptyProvider (jsonProp.valueDeserializer).getNullValue(ctxt)
79
- }
87
+ val propType = jsonProp.type
80
88
81
- val isGenericTypeVar = paramDef.type.javaType is TypeVariable <* >
82
- val isMissingAndRequired = paramVal == null && isMissing && jsonProp.isRequired
83
- if (isMissingAndRequired ||
84
- (! isGenericTypeVar && paramVal == null && ! paramDef.type.isMarkedNullable)) {
85
- throw MismatchedInputException .from(
86
- ctxt.parser,
87
- jsonProp.type,
88
- " Instantiation of $valueTypeDesc value failed for JSON property ${jsonProp.name} " +
89
- " due to missing (therefore NULL) value for creator parameter ${paramDef.name} " +
90
- " which is a non-nullable type"
91
- ).wrapWithPath(this .valueClass, jsonProp.name)
92
- }
89
+ if (paramVal == null ) {
90
+ if (propType.requireEmptyValue()) {
91
+ paramVal = NullsAsEmptyProvider (jsonProp.valueDeserializer).getNullValue(ctxt)
92
+ } else {
93
+ val isMissingAndRequired = isMissing && jsonProp.isRequired
94
+
95
+ // Since #310 reported that the calculation cost is high, isGenericTypeVar is determined last.
96
+ if (isMissingAndRequired || (! paramType.isMarkedNullable && ! paramType.isGenericTypeVar())) {
97
+ throw MismatchedInputException .from(
98
+ ctxt.parser,
99
+ propType,
100
+ " Instantiation of $valueTypeDesc value failed for JSON property ${jsonProp.name} " +
101
+ " due to missing (therefore NULL) value for creator parameter ${paramDef.name} " +
102
+ " which is a non-nullable type"
103
+ ).wrapWithPath(this .valueClass, jsonProp.name)
104
+ }
105
+ }
106
+ } else if (strictNullChecks) {
107
+ val arguments = paramType.arguments
93
108
94
- if (strictNullChecks && paramVal != null ) {
95
- var paramType: String? = null
109
+ var paramTypeStr: String? = null
96
110
var itemType: KType ? = null
97
- if (jsonProp.type.isCollectionLikeType && paramDef.type.arguments.getOrNull(0 )?.type?.isMarkedNullable == false && (paramVal as Collection <* >).any { it == null }) {
98
- paramType = " collection"
99
- itemType = paramDef.type.arguments[0 ].type
111
+
112
+ if (propType.isCollectionLikeType && arguments.markedNonNullAt(0 ) && (paramVal as Collection <* >).any { it == null }) {
113
+ paramTypeStr = " collection"
114
+ itemType = arguments[0 ].type
100
115
}
101
116
102
- if (jsonProp.type. isMapLikeType && paramDef.type. arguments.getOrNull (1 )?.type?.isMarkedNullable == false && (paramVal as Map <* , * >).any { it.value == null }) {
103
- paramType = " map"
104
- itemType = paramDef.type. arguments[1 ].type
117
+ if (propType. isMapLikeType && arguments.markedNonNullAt (1 ) && (paramVal as Map <* , * >).any { it.value == null }) {
118
+ paramTypeStr = " map"
119
+ itemType = arguments[1 ].type
105
120
}
106
121
107
- if (jsonProp.type. isArrayType && paramDef.type. arguments.getOrNull (0 )?.type?.isMarkedNullable == false && (paramVal as Array <* >).any { it == null }) {
108
- paramType = " array"
109
- itemType = paramDef.type. arguments[0 ].type
122
+ if (propType. isArrayType && arguments.markedNonNullAt (0 ) && (paramVal as Array <* >).any { it == null }) {
123
+ paramTypeStr = " array"
124
+ itemType = arguments[0 ].type
110
125
}
111
126
112
- if (paramType != null && itemType != null ) {
127
+ if (paramTypeStr != null && itemType != null ) {
113
128
throw MismatchedInputException .from(
114
129
ctxt.parser,
115
- jsonProp.type ,
116
- " Instantiation of $itemType $paramType failed for JSON property ${jsonProp.name} due to null value in a $paramType that does not allow null values"
130
+ propType ,
131
+ " Instantiation of $itemType $paramTypeStr failed for JSON property ${jsonProp.name} due to null value in a $paramTypeStr that does not allow null values"
117
132
).wrapWithPath(this .valueClass, jsonProp.name)
118
133
}
119
134
}
0 commit comments