Skip to content

Instantly share code, notes, and snippets.

@pfgray
Last active July 27, 2018 18:23
Show Gist options
  • Select an option

  • Save pfgray/51c4915effba9b4ed53f36943f01d669 to your computer and use it in GitHub Desktop.

Select an option

Save pfgray/51c4915effba9b4ed53f36943f01d669 to your computer and use it in GitHub Desktop.
/**
* ADT
*/
sealed trait MultipleOrOne[A] {
def exists(f: A => Boolean) =
this match {
case Multiple(all) => all.exists(f)
case One(one) => f(one)
}
}
case class Multiple[A](value: Seq[A]) extends MultipleOrOne[A]
case class One[A](value: A) extends MultipleOrOne[A]
/**
* Deserializer
*/
import com.fasterxml.jackson.core.{JsonToken, JsonParser}
import com.fasterxml.jackson.databind.`type`.CollectionType
import com.fasterxml.jackson.databind.deser.{ContextualDeserializer, Deserializers}
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind._
private class MultipleOrOneDeserializer(valueType: JavaType)
extends StdDeserializer[MultipleOrOne[Any]](classOf[MultipleOrOne[Any]])
with ContextualDeserializer {
override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[_] = {
val wrapperType = property.getType()
val containedType = wrapperType.containedType(0)
val deserializer = new MultipleOrOneDeserializer(containedType)
return deserializer
}
override def deserialize(jp: JsonParser, ctxt: DeserializationContext): MultipleOrOne[Any] =
jp.getCurrentToken match {
case JsonToken.VALUE_NULL => null
case JsonToken.START_ARRAY =>
//deserialize as seq w/ type
Multiple(getSeqDeserializer(valueType, ctxt).deserialize(jp, ctxt).asInstanceOf[Seq[Any]])
case _ =>
//deserialize a type
One(ctxt.findRootValueDeserializer(valueType).deserialize(jp, ctxt).asInstanceOf[Any])
}
def getSeqDeserializer(entityType: JavaType, ctxt: DeserializationContext) = {
val seqType = CollectionType.construct(classOf[Seq[_]], entityType)
ctxt.findRootValueDeserializer(seqType)
}
}
private object MultipleOrOneDeserializerResolver extends Deserializers.Base {
private val MULT_OR_ONE = classOf[MultipleOrOne[Any]]
override def findBeanDeserializer(javaType: JavaType, config: DeserializationConfig, beanDesc: BeanDescription) = {
val rawClass = javaType.getRawClass
if (!MULT_OR_ONE.isAssignableFrom(rawClass)) null
else new MultipleOrOneDeserializer(javaType)
}
}
/**
* Serializer
*/
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.databind.ser.Serializers
import com.fasterxml.jackson.databind.ser.std.StdSerializer
/**
* Serializes json into instances of [[MultipleOrOne]].
*/
private class MultipleOrOneSerializer extends StdSerializer[MultipleOrOne[Any]](classOf[MultipleOrOne[Any]]) {
override def handledType: Class[MultipleOrOne[Any]] = {
return classOf[MultipleOrOne[Any]]
}
override def serialize(input: MultipleOrOne[Any], jgen: JsonGenerator, provider: SerializerProvider): Unit = {
val unwrapped: Any = input match {
case Multiple(list) => list
case One(one) => one
}
provider.defaultSerializeValue(unwrapped, jgen)
}
}
private object MultipleOrOneSerializerResolver extends Serializers.Base {
private val MULT_OR_ONE = classOf[MultipleOrOne[_]]
override def findSerializer(config: SerializationConfig, javaType: JavaType, beanDesc: BeanDescription): JsonSerializer[_] ={
val rawClass = javaType.getRawClass
if (!MULT_OR_ONE.isAssignableFrom(rawClass)) null
else new MultipleOrOneSerializer()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment