Skip to content

Commit 01915e2

Browse files
committed
added new deserialization function and modified to call it separately
1 parent e7d73ac commit 01915e2

File tree

1 file changed

+95
-1
lines changed

1 file changed

+95
-1
lines changed

src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,92 @@ internal class KotlinValueInstantiator(
3232
private val strictNullChecks: Boolean,
3333
private val experimentalDeserializationBackend: Boolean
3434
) : StdValueInstantiator(src) {
35+
private fun experimentalCreateFromObjectWith(
36+
ctxt: DeserializationContext,
37+
props: Array<out SettableBeanProperty>,
38+
buffer: PropertyValueBuffer
39+
): Any? {
40+
val instantiator: Instantiator<*> = cache.instantiatorFromJava(_withArgsCreator)
41+
?: return super.createFromObjectWith(ctxt, props, buffer) // we cannot reflect this method so do the default Java-ish behavior
42+
43+
val bucket = instantiator.generateBucket()
44+
45+
instantiator.valueParameters.forEachIndexed { idx, paramDef ->
46+
val jsonProp = props[idx]
47+
val isMissing = !buffer.hasParameter(jsonProp)
48+
49+
if (isMissing && paramDef.isOptional) {
50+
return@forEachIndexed
51+
}
52+
53+
var paramVal = if (!isMissing || paramDef.isPrimitive() || jsonProp.hasInjectableValueId()) {
54+
val tempParamVal = buffer.getParameter(jsonProp)
55+
if (nullIsSameAsDefault && tempParamVal == null && paramDef.isOptional) {
56+
return@forEachIndexed
57+
}
58+
tempParamVal
59+
} else {
60+
// trying to get suitable "missing" value provided by deserializer
61+
jsonProp.valueDeserializer?.getNullValue(ctxt)
62+
}
63+
64+
if (paramVal == null && ((nullToEmptyCollection && jsonProp.type.isCollectionLikeType) || (nullToEmptyMap && jsonProp.type.isMapLikeType))) {
65+
paramVal = NullsAsEmptyProvider(jsonProp.valueDeserializer).getNullValue(ctxt)
66+
}
67+
68+
val isGenericTypeVar = paramDef.type.javaType is TypeVariable<*>
69+
val isMissingAndRequired = paramVal == null && isMissing && jsonProp.isRequired
70+
if (isMissingAndRequired ||
71+
(!isGenericTypeVar && paramVal == null && !paramDef.type.isMarkedNullable)) {
72+
throw MissingKotlinParameterException(
73+
parameter = paramDef,
74+
processor = ctxt.parser,
75+
msg = "Instantiation of ${this.valueTypeDesc} value failed for JSON property ${jsonProp.name} due to missing (therefore NULL) value for creator parameter ${paramDef.name} which is a non-nullable type"
76+
).wrapWithPath(this.valueClass, jsonProp.name)
77+
}
78+
79+
if (strictNullChecks && paramVal != null) {
80+
var paramType: String? = null
81+
var itemType: KType? = null
82+
if (jsonProp.type.isCollectionLikeType && paramDef.type.arguments.getOrNull(0)?.type?.isMarkedNullable == false && (paramVal as Collection<*>).any { it == null }) {
83+
paramType = "collection"
84+
itemType = paramDef.type.arguments[0].type
85+
}
86+
87+
if (jsonProp.type.isMapLikeType && paramDef.type.arguments.getOrNull(1)?.type?.isMarkedNullable == false && (paramVal as Map<*, *>).any { it.value == null }) {
88+
paramType = "map"
89+
itemType = paramDef.type.arguments[1].type
90+
}
91+
92+
if (jsonProp.type.isArrayType && paramDef.type.arguments.getOrNull(0)?.type?.isMarkedNullable == false && (paramVal as Array<*>).any { it == null }) {
93+
paramType = "array"
94+
itemType = paramDef.type.arguments[0].type
95+
}
96+
97+
if (paramType != null && itemType != null) {
98+
throw MissingKotlinParameterException(
99+
parameter = paramDef,
100+
processor = ctxt.parser,
101+
msg = "Instantiation of $itemType $paramType failed for JSON property ${jsonProp.name} due to null value in a $paramType that does not allow null values"
102+
).wrapWithPath(this.valueClass, jsonProp.name)
103+
}
104+
}
105+
106+
bucket[idx] = paramVal
107+
}
108+
109+
// TODO: Is it necessary to call them differently? Direct execution will perform better.
110+
return if (bucket.isFullInitialized() && !instantiator.hasInstanceParameter) {
111+
// we didn't do anything special with default parameters, do a normal call
112+
super.createFromObjectWith(ctxt, bucket.values)
113+
} else {
114+
instantiator.checkAccessibility(ctxt)
115+
instantiator.callBy(bucket)
116+
}
117+
}
118+
35119
@Suppress("UNCHECKED_CAST")
36-
override fun createFromObjectWith(
120+
private fun conventionalCreateFromObjectWith(
37121
ctxt: DeserializationContext,
38122
props: Array<out SettableBeanProperty>,
39123
buffer: PropertyValueBuffer
@@ -174,6 +258,16 @@ internal class KotlinValueInstantiator(
174258

175259
}
176260

261+
override fun createFromObjectWith(
262+
ctxt: DeserializationContext,
263+
props: Array<out SettableBeanProperty>,
264+
buffer: PropertyValueBuffer
265+
): Any? = if (experimentalDeserializationBackend) {
266+
experimentalCreateFromObjectWith(ctxt, props, buffer)
267+
} else {
268+
conventionalCreateFromObjectWith(ctxt, props, buffer)
269+
}
270+
177271
private fun KParameter.isPrimitive(): Boolean {
178272
return when (val javaType = type.javaType) {
179273
is Class<*> -> javaType.isPrimitive

0 commit comments

Comments
 (0)