Skip to content

Instantly share code, notes, and snippets.

@crimsoncor
Created August 13, 2012 18:48
Show Gist options
  • Save crimsoncor/3343166 to your computer and use it in GitHub Desktop.
Save crimsoncor/3343166 to your computer and use it in GitHub Desktop.
Patch to enable hacky keyserializer support for CaseClasses in the Jackson Scala module
From 5ec37ea1d859430b950cf49c8bba5bf8499522cc Mon Sep 17 00:00:00 2001
From: Jesse C <crimson.corelio@gmail.com>
Date: Mon, 13 Aug 2012 14:36:51 -0400
Subject: [PATCH] Hacky proof-of-concept for keySerializers in caseClasses
---
.../scala/deser/CaseClassDeserializerModule.scala | 41 ++++++++++++++++++++--
.../module/scala/ser/MapSerializerModule.scala | 23 ++++++++++--
2 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
index bdc2884..1736d69 100644
--- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
+++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
@@ -2,10 +2,10 @@ package com.fasterxml.jackson.module.scala.deser
import com.fasterxml.jackson.module.scala.JacksonModule
import com.fasterxml.jackson.module.scala.util.ScalaBeansUtil
-
-import com.fasterxml.jackson.databind.introspect.{AnnotatedField, AnnotatedConstructor, AnnotatedParameter, NopAnnotationIntrospector};
-
+import com.fasterxml.jackson.databind.introspect.{Annotated, AnnotatedField, AnnotatedConstructor, AnnotatedParameter, NopAnnotationIntrospector}
import org.scalastuff.scalabeans.{DeserializablePropertyDescriptor, ConstructorParameter}
+import com.fasterxml.jackson.databind.introspect.AnnotatedMethod
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
private object CaseClassAnnotationIntrospector extends NopAnnotationIntrospector {
lazy val PRODUCT = classOf[Product]
@@ -19,6 +19,39 @@ private object CaseClassAnnotationIntrospector extends NopAnnotationIntrospector
else if (cls.getName.startsWith("scala.Tuple")) false
else true
}
+
+ override def findKeySerializer(a: Annotated): Object = {
+ a match {
+ // If we're serializing a method, see if we have a constructor arg with the
+ // same name (we should). That will have any applicable annotations on it.
+ case am: AnnotatedMethod => {
+ val cls = am.getDeclaringClass
+ if (!maybeIsCaseClass(cls)) null
+ else {
+ val fieldName = am.getName
+ val properties = ScalaBeansUtil.propertiesOf(cls)
+ properties.find {
+ case cp: ConstructorParameter => fieldName == cp.name
+ case _ => false
+ } match {
+ case Some(prop) => {
+ val cp = prop.asInstanceOf[ConstructorParameter]
+ val idx = cp.index
+ val constructors = cls.getConstructors()
+ val paramAnnots = constructors.head.getParameterAnnotations
+ val pa = paramAnnots(idx)
+ val annot = pa.find {
+ case a => a.annotationType() == classOf[JsonSerialize]
+ }
+ annot.map(a => a.asInstanceOf[JsonSerialize].keyUsing) getOrElse null
+ }
+ case None => null
+ }
+ }
+ }
+ case _ => null
+ }
+ }
override def findDeserializationName(af: AnnotatedField): String = {
val cls = af.getDeclaringClass
@@ -32,6 +65,8 @@ private object CaseClassAnnotationIntrospector extends NopAnnotationIntrospector
} map (_.name) getOrElse null
}
}
+
+
override def findDeserializationName(param: AnnotatedParameter): String = {
val cls = param.getDeclaringClass
diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/MapSerializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/MapSerializerModule.scala
index 58c7366..bbb8211 100644
--- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/MapSerializerModule.scala
+++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/MapSerializerModule.scala
@@ -12,12 +12,26 @@ import com.fasterxml.jackson.databind.`type`.MapLikeType;
import com.fasterxml.jackson.module.scala.modifiers.MapTypeModifierModule;
-private class MapSerializer
+private class MapSerializer(val keySerializer: JsonSerializer[AnyRef])
extends JsonSerializer[Map[_,_]]
{
def serialize(value: Map[_, _], jgen: JsonGenerator, provider: SerializerProvider) {
jgen.writeStartObject()
- value.foreach { case (k,v) => jgen.writeObjectField(k.toString,v) }
+ value.foreach { case (k,v) => {
+ if (keySerializer == null) {
+ jgen.writeObjectField(k.toString,v)
+ }
+ else {
+ k match {
+ case a: AnyRef => {
+ keySerializer.serialize(a, jgen, provider)
+ jgen.writeObject(v)
+ }
+ case _ => jgen.writeObjectField(k.toString,v)
+ }
+
+ }
+ }}
jgen.writeEndObject()
}
@@ -37,9 +51,12 @@ private object MapSerializerResolver extends Serializers.Base {
val rawClass = mapLikeType.getRawClass
+
+ val keyType = mapLikeType.getKeyType
+ val handler = keyType.getValueHandler[Object]
if (!BASE.isAssignableFrom(rawClass)) null
- else new MapSerializer
+ else new MapSerializer(keySerializer)
}
}
--
1.7.11.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment