Skip to content

Fix regression in Map deserialization in Scala 2.13 when default typing is enabled #658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -14,13 +14,24 @@ import scala.collection.Map
private class MapConverter(inputType: JavaType, config: SerializationConfig)
extends StdConverter[Map[_,_],java.util.Map[_,_]]
{
// Making this an inner class avoids deserializaion errors when polymorphic typing
// is enabled. In Scala 2.12 `delegate.asJava` happened to be an inner class but
// this implementation detail changed in 2.13.
//
// Tested in DefaultTypingMapDeserializerTest
private class MapWrapper[A, B](delegate: Map[A, B]) extends java.util.AbstractMap[A, B] {
private val wrapped = delegate.asJava

override def entrySet(): java.util.Set[java.util.Map.Entry[A, B]] = wrapped.entrySet()
}

def convert(value: Map[_,_]): java.util.Map[_,_] = {
val m = if (config.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
value
} else {
value.filter(_._2 != None)
}
m.asJava
new MapWrapper(m)
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.fasterxml.jackson.module.scala.deser

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

import scala.collection.immutable

class DefaultTypingMapDeserializerTest extends DeserializerTest {

def module: DefaultScalaModule.type = DefaultScalaModule

override def newMapper: ObjectMapper = {
val mapper = super.newMapper
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator)
}

"Scala Module" should "deserialize immutable Map when default typing enabled" in {
val map = HasMap(immutable.Map("one" -> "one", "two" -> "two"))

val mapper = newMapper

val json = mapper.writeValueAsString(map)
// Was failing in Scala 2.13+ with:
// > Could not resolve type id 'scala.collection.convert.JavaCollectionWrappers$MapWrapper' as a subtype of
// > `scala.collection.immutable.Map<java.lang.String,java.lang.String>`: Not a subtype
//
// prior the changing MapSerializerModule.scala to use an inner class for MapWrapper
val read = mapper.readValue(json, classOf[HasMap])

read shouldEqual map
}

}

case class HasMap(m: Map[String, String])