Skip to content
Merged
Show file tree
Hide file tree
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
@@ -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._
Expand All @@ -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
}
})
}
Original file line number Diff line number Diff line change
@@ -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._
Expand All @@ -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
}
})
}
Original file line number Diff line number Diff line change
@@ -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._
Expand All @@ -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
}
})
}
Original file line number Diff line number Diff line change
@@ -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]]
}
}
Original file line number Diff line number Diff line change
@@ -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]]
}

}
Loading