From 477b0095ec16a392c9bcaca74d502a5c524e791d Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 30 Dec 2023 10:16:30 +0900 Subject: [PATCH 1/5] The vararg is skipped as well as optional parameters --- .../fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt index 06086531..a2384138 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt @@ -74,7 +74,7 @@ internal class KotlinValueInstantiator( tempParamVal } else { when { - paramDef.isOptional -> return@forEachIndexed + paramDef.isOptional || paramDef.isVararg -> return@forEachIndexed // do not try to create any object if it is nullable and the value is missing paramType.isMarkedNullable -> null // Primitive types always try to get from a buffer, considering several settings From 09511236c75327f151f3d7f9f5d1928030b3bd98 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 30 Dec 2023 10:16:47 +0900 Subject: [PATCH 2/5] Add deser test --- .../module/kotlin/test/VarargDeserTest.kt | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/VarargDeserTest.kt diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/VarargDeserTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/VarargDeserTest.kt new file mode 100644 index 00000000..0e9c067b --- /dev/null +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/VarargDeserTest.kt @@ -0,0 +1,117 @@ +package com.fasterxml.jackson.module.kotlin.test + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertTrue +import org.junit.Ignore +import org.junit.experimental.runners.Enclosed +import org.junit.runner.RunWith +import kotlin.test.Test + +// from https://github.com/ProjectMapK/jackson-module-kogera/blob/0631cd3b07c7fb6971a00ac1f6811b4367a1720e/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zIntegration/deser/VarargTest.kt#L1 +@RunWith(Enclosed::class) +class VarargDeserTest { + @Ignore + companion object { + val mapper = jacksonObjectMapper() + } + + @Ignore + class OnlyVararg(vararg val v: Int) + + class OnlyVarargTest { + @Test + fun hasArgs() { + val r = mapper.readValue("""{"v":[1,2,3]}""") + assertEquals(listOf(1, 2, 3), r.v.asList()) + } + + @Test + fun empty() { + val r = mapper.readValue("""{"v":[]}""") + assertTrue(r.v.isEmpty()) + } + + @Test + fun undefined() { + val r = mapper.readValue("""{}""") + assertTrue(r.v.isEmpty()) + } + } + + @Ignore + class HeadVararg(vararg val v: Int?, val i: Int) + + class HeadVarargTest { + @Test + fun hasArgs() { + val r = mapper.readValue("""{"i":0,"v":[1,2,null]}""") + assertEquals(listOf(1, 2, null), r.v.asList()) + assertEquals(0, r.i) + } + + @Test + fun empty() { + val r = mapper.readValue("""{"i":0,"v":[]}""") + assertTrue(r.v.isEmpty()) + assertEquals(0, r.i) + } + + @Test + fun undefined() { + val r = mapper.readValue("""{"i":0}""") + assertTrue(r.v.isEmpty()) + assertEquals(0, r.i) + } + } + + @Ignore + class TailVararg(val i: Int, vararg val v: String) + + class TailVarargTest { + @Test + fun hasArgs() { + val r = mapper.readValue("""{"i":0,"v":["foo","bar","baz"]}""") + assertEquals(listOf("foo", "bar", "baz"), r.v.asList()) + assertEquals(0, r.i) + } + + @Test + fun empty() { + val r = mapper.readValue("""{"i":0,"v":[]}""") + assertTrue(r.v.isEmpty()) + assertEquals(0, r.i) + } + + @Test + fun undefined() { + val r = mapper.readValue("""{"i":0}""") + assertTrue(r.v.isEmpty()) + assertEquals(0, r.i) + } + } + + @Ignore + class HasDefaultVararg(vararg val v: String? = arrayOf("foo", "bar")) + + class HasDefaultVarargTest { + @Test + fun hasArgs() { + val r = mapper.readValue("""{"v":["foo","bar",null]}""") + assertEquals(listOf("foo", "bar", null), r.v.asList()) + } + + @Test + fun empty() { + val r = mapper.readValue("""{"v":[]}""") + assertTrue(r.v.isEmpty()) + } + + @Test + fun undefined() { + val r = mapper.readValue("""{}""") + assertEquals(listOf("foo", "bar"), r.v.asList()) + } + } +} From 854d2a8ac03dbe9fa351a3a0491e9f0294b76352 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 30 Dec 2023 10:17:05 +0900 Subject: [PATCH 3/5] Fix vararg param requirement --- .../jackson/module/kotlin/KotlinAnnotationIntrospector.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt index 7af632b4..073ee2a9 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt @@ -207,13 +207,12 @@ internal class KotlinAnnotationIntrospector( private fun KFunction<*>.isParameterRequired(index: Int): Boolean { val param = parameters[index] val paramType = param.type - val javaType = paramType.javaType - val isPrimitive = when (javaType) { + val isPrimitive = when (val javaType = paramType.javaType) { is Class<*> -> javaType.isPrimitive else -> false } - return !paramType.isMarkedNullable && !param.isOptional && + return !paramType.isMarkedNullable && !param.isOptional && !param.isVararg && !(isPrimitive && !context.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) } From 2f9f035f0b497725be3954723543f5ad2c8c3955 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 30 Dec 2023 10:27:42 +0900 Subject: [PATCH 4/5] Add test case --- .../jackson/module/kotlin/test/PropertyRequirednessTests.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/PropertyRequirednessTests.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/PropertyRequirednessTests.kt index a3fe2e89..492609f0 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/PropertyRequirednessTests.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/PropertyRequirednessTests.kt @@ -76,7 +76,7 @@ class TestPropertyRequiredness { // --- - private data class TestDataClass( + private class TestDataClass( val a: Int, val b: Int?, val c: Int = 5, @@ -85,6 +85,7 @@ class TestPropertyRequiredness { val f: TestParamClass?, val g: TestParamClass = TestParamClass(), val h: TestParamClass? = TestParamClass(), + vararg val i: Int, @JsonProperty("x", required = true) val x: Int?, // TODO: either error in test case with this not being on the property getter, or error in introspection not seeing this on the constructor parameter @get:JsonProperty("z", required = true) val z: Int ) @@ -117,6 +118,9 @@ class TestPropertyRequiredness { "h".isOptionalForSerializationOf(testClass, mapper) "h".isOptionalForDeserializationOf(testClass, mapper) + "i".isRequiredForSerializationOf(testClass, mapper) + "i".isOptionalForDeserializationOf(testClass, mapper) + "x".isRequiredForDeserializationOf(testClass, mapper) "x".isOptionalForSerializationOf(testClass, mapper) From fd8ffdf085c559ec1b913506d4c2a50954c90d22 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 30 Dec 2023 11:07:44 +0900 Subject: [PATCH 5/5] Update release notes wrt #743 --- release-notes/CREDITS-2.x | 1 + release-notes/VERSION-2.x | 2 ++ 2 files changed, 3 insertions(+) diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 76d1c3d4..a1f588fc 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -18,6 +18,7 @@ Contributors: # 2.17.0 (not yet released) WrongWrong (@k163377) +* #743: Fix handling of vararg deserialization. * #742: Minor performance improvements to NullToEmptyCollection/Map. * #741: Changed to allow KotlinFeature to be set in the function that registers a KotlinModule. * #740: Reduce conversion cache from Executable to KFunction. diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 0e6d0099..7930a0aa 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -18,6 +18,8 @@ Co-maintainers: 2.17.0 (not yet released) +* #743: The handling of deserialization using vararg arguments has been improved to allow deserialization even when the input to the vararg argument is undefined. + In addition, vararg arguments are now reported as non-required. #742: Minor performance improvements to NullToEmptyCollection/Map. #741: Changed to allow KotlinFeature to be set in the function that registers a KotlinModule. The `jacksonObjectMapper {}` and `registerKotlinModule {}` lambdas allow configuration for KotlinModule.