diff --git a/src/main/scala-2.11/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala b/src/main/scala-2.11/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala index ceabcaab2..bca4f81a3 100644 --- a/src/main/scala-2.11/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala +++ b/src/main/scala-2.11/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala @@ -1,6 +1,8 @@ package com.fasterxml.jackson.module.scala.deser import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer import com.fasterxml.jackson.module.scala.modifiers.MapTypeModifierModule import scala.collection._ @@ -27,5 +29,25 @@ trait UnsortedMapDeserializerModule extends MapTypeModifierModule { )) override def builderFor[K, V](factory: Factory, keyType: JavaType, valueType: JavaType): Builder[K, V] = factory.newBuilder[K, V] + + override def findMapLikeDeserializer(theType: MapLikeType, + config: DeserializationConfig, + beanDesc: BeanDescription, + keyDeserializer: KeyDeserializer, + elementTypeDeserializer: TypeDeserializer, + elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { + + var deserializer = LongMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = IntMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = super.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + } + } + deserializer + } }) } diff --git a/src/main/scala-2.12/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala b/src/main/scala-2.12/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala index ceabcaab2..bca4f81a3 100644 --- a/src/main/scala-2.12/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala +++ b/src/main/scala-2.12/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala @@ -1,6 +1,8 @@ package com.fasterxml.jackson.module.scala.deser import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer import com.fasterxml.jackson.module.scala.modifiers.MapTypeModifierModule import scala.collection._ @@ -27,5 +29,25 @@ trait UnsortedMapDeserializerModule extends MapTypeModifierModule { )) override def builderFor[K, V](factory: Factory, keyType: JavaType, valueType: JavaType): Builder[K, V] = factory.newBuilder[K, V] + + override def findMapLikeDeserializer(theType: MapLikeType, + config: DeserializationConfig, + beanDesc: BeanDescription, + keyDeserializer: KeyDeserializer, + elementTypeDeserializer: TypeDeserializer, + elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { + + var deserializer = LongMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = IntMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = super.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + } + } + deserializer + } }) } diff --git a/src/main/scala-2.13/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala b/src/main/scala-2.13/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala index f4c4e50eb..b3ca4fe51 100644 --- a/src/main/scala-2.13/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala +++ b/src/main/scala-2.13/com/fasterxml/jackson/module/scala/deser/UnsortedMapDeserializerModule.scala @@ -1,6 +1,8 @@ package com.fasterxml.jackson.module.scala.deser import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer import com.fasterxml.jackson.module.scala.modifiers.MapTypeModifierModule import scala.collection._ @@ -26,5 +28,25 @@ trait UnsortedMapDeserializerModule extends MapTypeModifierModule { )) override def builderFor[K, V](factory: Factory, keyType: JavaType, valueType: JavaType): Builder[K, V] = factory.newBuilder[K, V] + + override def findMapLikeDeserializer(theType: MapLikeType, + config: DeserializationConfig, + beanDesc: BeanDescription, + keyDeserializer: KeyDeserializer, + elementTypeDeserializer: TypeDeserializer, + elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { + + var deserializer = LongMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = IntMapDeserializerResolver.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + if (deserializer == null) { + deserializer = super.findMapLikeDeserializer( + theType, config, beanDesc, keyDeserializer, elementTypeDeserializer, elementDeserializer) + } + } + deserializer + } }) } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerReseolver.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerReseolver.scala new file mode 100644 index 000000000..5947fed4d --- /dev/null +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerReseolver.scala @@ -0,0 +1,105 @@ +package com.fasterxml.jackson.module.scala.deser + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.deser.{ContextualDeserializer, Deserializers} +import com.fasterxml.jackson.databind.deser.std.{ContainerDeserializerBase, MapDeserializer, StdValueInstantiator} +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer +import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.module.scala.{DefaultScalaModule, IteratorModule} + +import java.util +import scala.collection.JavaConverters._ +import scala.collection.immutable.IntMap + +/** + * Adds support for deserializing Scala [[scala.collection.immutable.IntMap]]s. Scala IntMaps can already be + * serialized using [[IteratorModule]] or [[DefaultScalaModule]]. + * + * @since 2.14.0 + */ +private[deser] object IntMapDeserializerResolver extends Deserializers.Base { + + private val intMapClass = classOf[IntMap[_]] + + override def findMapLikeDeserializer(theType: MapLikeType, + config: DeserializationConfig, + beanDesc: BeanDescription, + keyDeserializer: KeyDeserializer, + elementTypeDeserializer: TypeDeserializer, + elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { + if (!intMapClass.isAssignableFrom(theType.getRawClass)) None.orNull + else { + val mapDeserializer = new MapDeserializer(theType, new IntMapInstantiator(config, theType), keyDeserializer, + elementDeserializer.asInstanceOf[JsonDeserializer[AnyRef]], elementTypeDeserializer) + new IntMapDeserializer(theType, mapDeserializer) + } + } + + private class IntMapDeserializer[V](mapType: MapLikeType, containerDeserializer: MapDeserializer) + extends ContainerDeserializerBase[IntMap[V]](mapType) with ContextualDeserializer { + + override def getContentType: JavaType = containerDeserializer.getContentType + + override def getContentDeserializer: JsonDeserializer[AnyRef] = containerDeserializer.getContentDeserializer + + override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[_] = { + val newDelegate = containerDeserializer.createContextual(ctxt, property).asInstanceOf[MapDeserializer] + new IntMapDeserializer(mapType, newDelegate) + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext): IntMap[V] = { + containerDeserializer.deserialize(jp, ctxt) match { + case wrapper: BuilderWrapper => wrapper.asIntMap() + } + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext, intoValue: IntMap[V]): IntMap[V] = { + val newMap = deserialize(jp, ctxt) + if (newMap.isEmpty) { + intoValue + } else { + intoValue ++ newMap + } + } + + override def getEmptyValue(ctxt: DeserializationContext): Object = IntMap.empty[V] + } + + private class IntMapInstantiator(config: DeserializationConfig, mapType: MapLikeType) extends StdValueInstantiator(config, mapType) { + override def canCreateUsingDefault = true + override def createUsingDefault(ctxt: DeserializationContext) = new BuilderWrapper + } + + private class BuilderWrapper extends util.AbstractMap[Object, Object] { + var baseMap = IntMap[Object]() + + override def put(k: Object, v: Object): Object = { + k match { + case n: Number => baseMap += (n.intValue() -> v) + case s: String => baseMap += (s.toInt -> v) + case _ => { + val typeName = Option(k) match { + case Some(n) => n.getClass.getName + case _ => "null" + } + throw new IllegalArgumentException(s"IntMap does npt support keys of type $typeName") + } + } + v + } + + // Used by the deserializer when using readerForUpdating + override def get(key: Object): Object = key match { + case n: Number => baseMap.get(n.intValue()).orNull + case s: String => baseMap.get(s.toInt).orNull + case _ => None.orNull + } + + // Isn't used by the deserializer + override def entrySet(): java.util.Set[java.util.Map.Entry[Object, Object]] = + baseMap.asJava.entrySet().asInstanceOf[java.util.Set[java.util.Map.Entry[Object, Object]]] + + def asIntMap[V](): IntMap[V] = baseMap.asInstanceOf[IntMap[V]] + } +} diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerResolver.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerResolver.scala new file mode 100644 index 000000000..cd8c781be --- /dev/null +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerResolver.scala @@ -0,0 +1,180 @@ +package com.fasterxml.jackson.module.scala.deser + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.`type`.MapLikeType +import com.fasterxml.jackson.databind.deser.{ContextualDeserializer, Deserializers} +import com.fasterxml.jackson.databind.deser.std.{ContainerDeserializerBase, MapDeserializer, StdValueInstantiator} +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer +import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.module.scala.{DefaultScalaModule, IteratorModule} + +import java.util +import scala.collection.{immutable, mutable} +import scala.collection.JavaConverters._ + +/** + * Adds support for deserializing Scala [[scala.collection.immutable.LongMap]]s and [[scala.collection.mutable.LongMap]]s. + * Scala LongMaps can already be serialized using [[IteratorModule]] or [[DefaultScalaModule]]. + * + * @since 2.14.0 + */ +private[deser] object LongMapDeserializerResolver extends Deserializers.Base { + + private val immutableLongMapClass = classOf[immutable.LongMap[_]] + private val mutableLongMapClass = classOf[mutable.LongMap[_]] + + override def findMapLikeDeserializer(theType: MapLikeType, + config: DeserializationConfig, + beanDesc: BeanDescription, + keyDeserializer: KeyDeserializer, + elementTypeDeserializer: TypeDeserializer, + elementDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { + if (immutableLongMapClass.isAssignableFrom(theType.getRawClass)) { + val mapDeserializer = new MapDeserializer(theType, new ImmutableLongMapInstantiator(config, theType), keyDeserializer, + elementDeserializer.asInstanceOf[JsonDeserializer[AnyRef]], elementTypeDeserializer) + new ImmutableLongMapDeserializer(theType, mapDeserializer) + } else if (mutableLongMapClass.isAssignableFrom(theType.getRawClass)) { + val mapDeserializer = new MapDeserializer(theType, new MutableLongMapInstantiator(config, theType), keyDeserializer, + elementDeserializer.asInstanceOf[JsonDeserializer[AnyRef]], elementTypeDeserializer) + new MutableLongMapDeserializer(theType, mapDeserializer) + } else { + None.orNull + } + } + + private class ImmutableLongMapDeserializer[V](mapType: MapLikeType, containerDeserializer: MapDeserializer) + extends ContainerDeserializerBase[immutable.LongMap[V]](mapType) with ContextualDeserializer { + + override def getContentType: JavaType = containerDeserializer.getContentType + + override def getContentDeserializer: JsonDeserializer[AnyRef] = containerDeserializer.getContentDeserializer + + override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[_] = { + val newDelegate = containerDeserializer.createContextual(ctxt, property).asInstanceOf[MapDeserializer] + new ImmutableLongMapDeserializer(mapType, newDelegate) + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext): immutable.LongMap[V] = { + containerDeserializer.deserialize(jp, ctxt) match { + case wrapper: ImmutableMapWrapper => wrapper.asLongMap() + } + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext, intoValue: immutable.LongMap[V]): immutable.LongMap[V] = { + val newMap = deserialize(jp, ctxt) + if (newMap.isEmpty) { + intoValue + } else { + intoValue ++ newMap + } + } + + override def getEmptyValue(ctxt: DeserializationContext): Object = immutable.LongMap.empty[V] + } + + private class MutableLongMapDeserializer[V](mapType: MapLikeType, containerDeserializer: MapDeserializer) + extends ContainerDeserializerBase[mutable.LongMap[V]](mapType) with ContextualDeserializer { + + override def getContentType: JavaType = containerDeserializer.getContentType + + override def getContentDeserializer: JsonDeserializer[AnyRef] = containerDeserializer.getContentDeserializer + + override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[_] = { + val newDelegate = containerDeserializer.createContextual(ctxt, property).asInstanceOf[MapDeserializer] + new MutableLongMapDeserializer(mapType, newDelegate) + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext): mutable.LongMap[V] = { + containerDeserializer.deserialize(jp, ctxt) match { + case wrapper: MutableMapWrapper => wrapper.asLongMap() + } + } + + override def deserialize(jp: JsonParser, ctxt: DeserializationContext, intoValue: mutable.LongMap[V]): mutable.LongMap[V] = { + val newMap = deserialize(jp, ctxt) + if (newMap.isEmpty) { + intoValue + } else { + intoValue ++ newMap + } + } + + override def getEmptyValue(ctxt: DeserializationContext): Object = mutable.LongMap.empty[V] + } + + private class ImmutableLongMapInstantiator(config: DeserializationConfig, mapType: MapLikeType) extends StdValueInstantiator(config, mapType) { + override def canCreateUsingDefault = true + override def createUsingDefault(ctxt: DeserializationContext) = new ImmutableMapWrapper + } + + private class MutableLongMapInstantiator(config: DeserializationConfig, mapType: MapLikeType) extends StdValueInstantiator(config, mapType) { + override def canCreateUsingDefault = true + + override def createUsingDefault(ctxt: DeserializationContext) = new MutableMapWrapper + } + + private class ImmutableMapWrapper extends util.AbstractMap[Object, Object] { + var baseMap = immutable.LongMap[Object]() + + override def put(k: Object, v: Object): Object = { + k match { + case n: Number => baseMap += (n.longValue() -> v) + case s: String => baseMap += (s.toLong -> v) + case _ => { + val typeName = Option(k) match { + case Some(n) => n.getClass.getName + case _ => "null" + } + throw new IllegalArgumentException(s"IntMap does npt support keys of type $typeName") + } + } + v + } + + // Used by the deserializer when using readerForUpdating + override def get(key: Object): Object = key match { + case n: Number => baseMap.get(n.longValue()).orNull + case s: String => baseMap.get(s.toInt).orNull + case _ => None.orNull + } + + // Isn't used by the deserializer + override def entrySet(): java.util.Set[java.util.Map.Entry[Object, Object]] = + baseMap.asJava.entrySet().asInstanceOf[java.util.Set[java.util.Map.Entry[Object, Object]]] + + def asLongMap[V](): immutable.LongMap[V] = baseMap.asInstanceOf[immutable.LongMap[V]] + } + + private class MutableMapWrapper extends util.AbstractMap[Object, Object] { + var baseMap = mutable.LongMap[Object]() + + override def put(k: Object, v: Object): Object = { + k match { + case n: Number => baseMap += (n.longValue() -> v) + case s: String => baseMap += (s.toLong -> v) + case _ => { + val typeName = Option(k) match { + case Some(n) => n.getClass.getName + case _ => "null" + } + throw new IllegalArgumentException(s"IntMap does npt support keys of type $typeName") + } + } + v + } + + // Used by the deserializer when using readerForUpdating + override def get(key: Object): Object = key match { + case n: Number => baseMap.get(n.longValue()).orNull + case s: String => baseMap.get(s.toInt).orNull + case _ => None.orNull + } + + // Isn't used by the deserializer + override def entrySet(): java.util.Set[java.util.Map.Entry[Object, Object]] = + baseMap.asJava.entrySet().asInstanceOf[java.util.Set[java.util.Map.Entry[Object, Object]]] + + def asLongMap[V](): mutable.LongMap[V] = baseMap.asInstanceOf[mutable.LongMap[V]] + } + +} diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/ScalaTypeModifier.scala b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/ScalaTypeModifier.scala index 930571491..f34151806 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/ScalaTypeModifier.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/modifiers/ScalaTypeModifier.scala @@ -1,18 +1,23 @@ package com.fasterxml.jackson.module.scala.modifiers -import java.lang.reflect.Type - import com.fasterxml.jackson.databind.JavaType import com.fasterxml.jackson.databind.`type`._ import com.fasterxml.jackson.module.scala.JacksonModule +import java.lang.reflect.Type import scala.collection._ +import scala.collection.immutable.IntMap class ScalaTypeModifier extends TypeModifier { private val optionClass = classOf[Option[_]] private val eitherClass = classOf[Either[_, _]] private val mapClass = classOf[Map[_, _]] + private val intClass = classOf[Int] + private val intMapClass = classOf[IntMap[_]] + private val longClass = classOf[Long] + private val immutableLongMapClass = classOf[immutable.LongMap[_]] + private val mutableLongMapClass = classOf[mutable.LongMap[_]] private val iterableOnceClass = classOf[IterableOnce[_]] override def modifyType(javaType: JavaType, @@ -27,7 +32,13 @@ class ScalaTypeModifier extends TypeModifier { case _ => ReferenceType.upgradeFrom(javaType, javaType.containedTypeOrUnknown(0)) } } else if (javaType.isTypeOrSubTypeOf(mapClass)) { - MapLikeType.upgradeFrom(javaType, javaType.containedTypeOrUnknown(0), javaType.containedTypeOrUnknown(1)) + if (javaType.isTypeOrSubTypeOf(intMapClass)) { + MapLikeType.upgradeFrom(javaType, typeFactory.constructType(intClass), javaType.containedTypeOrUnknown(0)) + } else if (javaType.isTypeOrSubTypeOf(immutableLongMapClass) || javaType.isTypeOrSubTypeOf(mutableLongMapClass)) { + MapLikeType.upgradeFrom(javaType, typeFactory.constructType(longClass), javaType.containedTypeOrUnknown(0)) + } else { + MapLikeType.upgradeFrom(javaType, javaType.containedTypeOrUnknown(0), javaType.containedTypeOrUnknown(1)) + } } else if (javaType.isTypeOrSubTypeOf(iterableOnceClass)) { CollectionLikeType.upgradeFrom(javaType, javaType.containedTypeOrUnknown(0)) } else if (javaType.isTypeOrSubTypeOf(eitherClass)) { diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerTest.scala new file mode 100644 index 000000000..43e73ef2e --- /dev/null +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/IntMapDeserializerTest.scala @@ -0,0 +1,66 @@ +package com.fasterxml.jackson.module.scala.deser + +import com.fasterxml.jackson.core.`type`.TypeReference +import com.fasterxml.jackson.module.scala.DefaultScalaModule +import com.fasterxml.jackson.module.scala.deser.IntMapDeserializerTest.IntMapWrapper + +import scala.collection.immutable.IntMap + +object IntMapDeserializerTest { + case class IntMapWrapper(values: IntMap[Long]) +} + +class IntMapDeserializerTest extends DeserializerTest { + + def module: DefaultScalaModule.type = DefaultScalaModule + + "Scala Module" should "deserialize IntMap" in { + val map = IntMap(1 -> "one", 2 -> "two") + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[IntMap[String]]{}) + + read shouldBe map + } + + it should "deserialize IntMap (long value)" in { + val map = IntMap(1 -> 100L, 2 -> 200L) + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[IntMap[Long]] {}) + + read shouldEqual map + // next line fails due to type erasure (values are ints and won't cast to longs) + //read.values.sum shouldEqual map.values.sum + } + + it should "deserialize IntMapWrapper" in { + val map = IntMap(1 -> 100L, 2 -> 200L) + val instance = IntMapWrapper(map) + + val mapper = newMapper + + val json = mapper.writeValueAsString(instance) + val read = mapper.readValue(json, classOf[IntMapWrapper]) + + read shouldEqual instance + // next line fails due to type erasure (values are ints and won't cast to longs) + //read.values.values.sum shouldEqual map.values.sum + } + + it should "deserialize IntMap (bigint value)" in { + val map = IntMap(1 -> 100L, 2 -> 200L) + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[IntMap[BigInt]] {}) + + read shouldEqual map + read.values.sum shouldEqual map.values.sum + } +} diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerTest.scala new file mode 100644 index 000000000..bcc1adae6 --- /dev/null +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/LongMapDeserializerTest.scala @@ -0,0 +1,57 @@ +package com.fasterxml.jackson.module.scala.deser + +import com.fasterxml.jackson.core.`type`.TypeReference +import com.fasterxml.jackson.module.scala.DefaultScalaModule + +import scala.collection.{immutable, mutable} + +class LongMapDeserializerTest extends DeserializerTest { + + def module: DefaultScalaModule.type = DefaultScalaModule + + "Scala Module" should "deserialize immutable LongMap" in { + val map = immutable.LongMap(1L -> "one", 2L -> "two") + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[immutable.LongMap[String]] {}) + + read shouldEqual map + } + + it should "deserialize immutable LongMap (bigint)" in { + val map = immutable.LongMap(1L -> 100, 2L -> 200) + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[immutable.LongMap[BigInt]] {}) + + read shouldEqual map + read.values.sum shouldEqual map.values.sum + } + + it should "deserialize mutable LongMap" in { + val map = mutable.LongMap(1L -> "one", 2L -> "two") + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[mutable.LongMap[String]] {}) + + read shouldEqual map + } + + it should "deserialize mutable LongMap (bigint)" in { + val map = mutable.LongMap(1L -> 100, 2L -> 200) + + val mapper = newMapper + + val json = mapper.writeValueAsString(map) + val read = mapper.readValue(json, new TypeReference[mutable.LongMap[BigInt]] {}) + + read shouldEqual map + read.values.sum shouldEqual map.values.sum + } +}