Created
August 13, 2012 18:48
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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