From ece4c8a10b8eb7082053c5f12fc1477e49a226f6 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 13 May 2025 19:39:56 +0100 Subject: [PATCH 1/2] fix issue with FAIL_ON_NULL_CREATOR_PROPERTIES for collections --- .../GenericFactoryDeserializerResolver.scala | 7 ++++++- .../GenericMapFactoryDeserializerResolver.scala | 7 ++++++- .../scala/deser/CaseClassDeserializerTest.scala | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/scala/tools/jackson/module/scala/deser/GenericFactoryDeserializerResolver.scala b/src/main/scala/tools/jackson/module/scala/deser/GenericFactoryDeserializerResolver.scala index 5ca49223..1f5ddef3 100644 --- a/src/main/scala/tools/jackson/module/scala/deser/GenericFactoryDeserializerResolver.scala +++ b/src/main/scala/tools/jackson/module/scala/deser/GenericFactoryDeserializerResolver.scala @@ -145,7 +145,12 @@ abstract class GenericFactoryDeserializerResolver[CC[_], CF[X[_]]](config: Scala bw.builder.result().asInstanceOf[Object] } - override def getNullValue(ctxt: DeserializationContext): Object = getEmptyValue(ctxt) + override def getNullValue(ctxt: DeserializationContext): Object = { + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) + super.getNullValue(ctxt) + else + getEmptyValue(ctxt) + } private def newBuilderWrapper(ctxt: DeserializationContext): BuilderWrapper[AnyRef] = { containerDeserializer.getValueInstantiator.createUsingDefault(ctxt).asInstanceOf[BuilderWrapper[AnyRef]] diff --git a/src/main/scala/tools/jackson/module/scala/deser/GenericMapFactoryDeserializerResolver.scala b/src/main/scala/tools/jackson/module/scala/deser/GenericMapFactoryDeserializerResolver.scala index b0bd611d..5df887f3 100644 --- a/src/main/scala/tools/jackson/module/scala/deser/GenericMapFactoryDeserializerResolver.scala +++ b/src/main/scala/tools/jackson/module/scala/deser/GenericMapFactoryDeserializerResolver.scala @@ -166,7 +166,12 @@ abstract class GenericMapFactoryDeserializerResolver[CC[K, V], CF[X[_, _]]](conf bw.builder.result().asInstanceOf[Object] } - override def getNullValue(ctxt: DeserializationContext): Object = getEmptyValue(ctxt) + override def getNullValue(ctxt: DeserializationContext): Object = { + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) + super.getNullValue(ctxt) + else + getEmptyValue(ctxt) + } private def newBuilderWrapper(ctxt: DeserializationContext): BuilderWrapper[AnyRef, AnyRef] = { containerDeserializer.getValueInstantiator.createUsingDefault(ctxt).asInstanceOf[BuilderWrapper[AnyRef, AnyRef]] diff --git a/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala b/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala index e586b14a..8b0e81c9 100644 --- a/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala +++ b/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala @@ -210,6 +210,14 @@ class CaseClassDeserializerTest extends DeserializerTest { result.list shouldBe List.empty } + it should "fail when deserializing null input for list if FAIL_ON_NULL_CREATOR_PROPERTIES enabled" in { + val input = """{}""" + val mapper = newBuilder.enable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES).build() + intercept[com.fasterxml.jackson.databind.exc.MismatchedInputException] { + mapper.readValue(input, classOf[ListHolder[String]]) + } + } + it should "support deserializing null input for list as empty list (JsonSetter annotation)" in { val input = """{}""" val result = deserialize(input, classOf[AnnotatedListHolder[String]]) @@ -240,4 +248,12 @@ class CaseClassDeserializerTest extends DeserializerTest { val result = deserialize(input, classOf[AnnotatedMapHolder[Int, String]]) result.map shouldBe Map.empty } + + it should "fail when deserializing null input for map if FAIL_ON_NULL_CREATOR_PROPERTIES enabled" in { + val input = """{}""" + val mapper = newBuilder.enable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES).build() + intercept[com.fasterxml.jackson.databind.exc.MismatchedInputException] { + mapper.readValue(input, classOf[MapHolder[Int, String]]) + } + } } From b3cc08f5afec262c55757f613762b7df331f516d Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 13 May 2025 20:33:51 +0100 Subject: [PATCH 2/2] Update CaseClassDeserializerTest.scala --- .../module/scala/deser/CaseClassDeserializerTest.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala b/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala index 8b0e81c9..8aeab8d2 100644 --- a/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala +++ b/src/test/scala/tools/jackson/module/scala/deser/CaseClassDeserializerTest.scala @@ -213,7 +213,7 @@ class CaseClassDeserializerTest extends DeserializerTest { it should "fail when deserializing null input for list if FAIL_ON_NULL_CREATOR_PROPERTIES enabled" in { val input = """{}""" val mapper = newBuilder.enable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES).build() - intercept[com.fasterxml.jackson.databind.exc.MismatchedInputException] { + intercept[tools.jackson.databind.exc.MismatchedInputException] { mapper.readValue(input, classOf[ListHolder[String]]) } } @@ -252,7 +252,7 @@ class CaseClassDeserializerTest extends DeserializerTest { it should "fail when deserializing null input for map if FAIL_ON_NULL_CREATOR_PROPERTIES enabled" in { val input = """{}""" val mapper = newBuilder.enable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES).build() - intercept[com.fasterxml.jackson.databind.exc.MismatchedInputException] { + intercept[tools.jackson.databind.exc.MismatchedInputException] { mapper.readValue(input, classOf[MapHolder[Int, String]]) } }