Permalink
Browse files

added some comments, referring to the original author Greg Zoller, an…

…d some README info.
  • Loading branch information...
1 parent e31fbf2 commit 7cef47c6548c4d913f1eb55346316c141b21a981 @daveclay daveclay committed Feb 8, 2011
View
12 README
@@ -1 +1,13 @@
Project to build Jackson (http://jackson.codehaus.org) module (jar) that supports Scala (http://www.scala-lang.org/) data types.
+
+The Scala Module supports serialization and limited deserialization of Scala Lists, Maps, and other immutable and mutable collection types. Scala's collection API does not inheret from Java's collection API; therefore this module is necessary to support Scala. For documentation on usage, please refer to the scala test cases:
+
+src/test/scala/com/fasterxml/jackson/module/scala/SerializationTest.scala
+src/test/scala/com/fasterxml/jackson/module/scala/DeserializationTest.scala
+
+To use the Scala Module in Jackson, simply register it with the ObjectMapper instance:
+
+val mapper = new ObjectMapper()
+mapper.registerModule(new ScalaModule())
+
+ObjectMapper methods readValue and writeValue will use the ScalaModule's ScalaDeserializers and ScalaSerializers to implement the Scala collection conversions.
@@ -2,51 +2,74 @@ package com.fasterxml.jackson.module.scala.deser
import java.lang.Class
import org.codehaus.jackson.JsonNode
-import com.fasterxml.jackson.module.scala.ser.ScalaMapSerializer
import org.codehaus.jackson.map._
import `type`.{ArrayType, CollectionType, MapType}
import deser.{CustomDeserializerFactory}
import org.codehaus.jackson.`type`.JavaType
/**
+ * The ScalaDeserialziers finds implementations of JsonDeserializer that can be used to parse JSON into Scala
+ * collections, specifically json to Map and json to Iterable.
*/
-
class ScalaDeserializers extends CustomDeserializerFactory with Deserializers {
- /*
- if (classOf[collection.Map[String, Any]].isAssignableFrom(clazz)) {
- } else if (classOf[Iterable[Any]].isAssignableFrom(clazz)) {
- } else if (classOf[Option[Any]].isAssignableFrom(clazz)) {
- } else if (classOf[scala.Enumeration$Val].isAssignableFrom(clazz)) {
- } else {
- }
- */
- def findBeanDeserializer(javaType: JavaType, config: DeserializationConfig, provider: DeserializerProvider, beanDesc: BeanDescription, property: BeanProperty) = {
+ /**
+ * findBeanDeserializer is called when the ObjectMapper determines the type is not recognized. Since the Scala
+ * collections types do not inherent from the base Java collections API, Jackson will just default to this method.
+ *
+ * This method determines what particular Scala type is being requested for deserialization, then finds its own
+ * Scala-based deserializer.
+ */
+ def findBeanDeserializer(javaType: JavaType,
+ config: DeserializationConfig,
+ provider: DeserializerProvider,
+ beanDesc: BeanDescription,
+ property: BeanProperty) = {
+
val clazz = javaType.getRawClass
var deserializer : JsonDeserializer[_] = null;
if (classOf[collection.Map[String, Any]].isAssignableFrom(clazz)) {
- val sig = javaType.getGenericSignature
- val keyType = javaType.containedType(0)
- val valueType = javaType.containedType(1)
- val keyDeser = provider.findKeyDeserializer(config, keyType, property)
- val valueDeser = provider.findValueDeserializer(config, valueType, property)
- val valueTypeDeser = null // TODO: will this be a problem?
- deserializer = new ScalaMapDeserializer(javaType, keyDeser, valueDeser, valueTypeDeser)
+ // Note: Since Map also implements Iterable, make sure we're checking Map before Iterable.
+ deserializer = findMapDeserializer(javaType, config, provider, beanDesc, property)
} else if (classOf[Iterable[Any]].isAssignableFrom(clazz)) {
- val sig = javaType.getGenericSignature
- val contentType = javaType.containedType(0)
- val contentDeser = provider.findValueDeserializer(config, contentType, property)
- val valueTypeDeser = null
- deserializer = new ScalaListDeserializer(javaType, contentDeser, valueTypeDeser)
+ deserializer = findIterableDeserializer(javaType, config, provider, beanDesc, property)
} else if (classOf[Option[Any]].isAssignableFrom(clazz)) {
+ // Todo:
} else if (classOf[scala.Enumeration$Val].isAssignableFrom(clazz)) {
+ // Todo:
}
deserializer
}
+ private def findMapDeserializer(javaType: JavaType,
+ config: DeserializationConfig,
+ provider: DeserializerProvider,
+ beanDesc: BeanDescription,
+ property: BeanProperty) = {
+ val sig = javaType.getGenericSignature
+ val keyType = javaType.containedType(0)
+ val valueType = javaType.containedType(1)
+ val keyDeser = provider.findKeyDeserializer(config, keyType, property)
+ val valueDeser = provider.findValueDeserializer(config, valueType, property)
+ val valueTypeDeser = null // TODO: will this be a problem?
+ new ScalaMapDeserializer(javaType, keyDeser, valueDeser, valueTypeDeser)
+ }
+
+ private def findIterableDeserializer(javaType: JavaType,
+ config: DeserializationConfig,
+ provider: DeserializerProvider,
+ beanDesc: BeanDescription,
+ property: BeanProperty) = {
+ val sig = javaType.getGenericSignature
+ val contentType = javaType.containedType(0)
+ val contentDeser = provider.findValueDeserializer(config, contentType, property)
+ val valueTypeDeser = null // TODO: will this be a problem?
+ new ScalaListDeserializer(javaType, contentDeser, valueTypeDeser)
+ }
+
def findTreeNodeDeserializer(nodeType: Class[_ <: JsonNode], config: DeserializationConfig, property: BeanProperty) = {
null
}
@@ -2,28 +2,39 @@ package com.fasterxml.jackson.module.scala.deser
import org.codehaus.jackson.`type`.JavaType
import org.codehaus.jackson.map._
-import deser.{CollectionDeserializer, StdDeserializer}
+import deser.CollectionDeserializer
import java.lang.reflect.Constructor
import java.util.Collection
import collection.JavaConversions._
import collection.mutable.ListBuffer
import org.codehaus.jackson._
-import collection.JavaConversions
+/**
+ * The ScalaListDeserializer deserializes json arrays into Scala Iterables.
+ */
class ScalaListDeserializer(val collectionType: JavaType,
- val valueDeser: JsonDeserializer[Object],
- val valueTypeDeser: TypeDeserializer) extends JsonDeserializer[collection.Iterable[Object]] {
+ val valueDeser: JsonDeserializer[Object],
+ val valueTypeDeser: TypeDeserializer) extends JsonDeserializer[collection.Iterable[Object]] {
+ // Note/Todo: I'm making an assumption here: I know the implementation of the CollectionDeserializer doesn't use the
+ // Constructor if I don't call the main deserialize() method, but instead call the one where I can pass in a Collection.
val constructor: Constructor[Collection[Object]] = null;
- val javaCollectionDeserializer = new CollectionDeserializer(collectionType, valueDeser, valueTypeDeser, constructor)
+ // The wrapped deserializer. I'll just use it, rather than copy-and-paste. Keep it DRY.
+ val javaCollectionDeserializer = new CollectionDeserializer(collectionType, valueDeser, valueTypeDeser, constructor)
override def deserialize(jp: JsonParser, ctxt: DeserializationContext) : collection.Iterable[Object] = {
+ // Todo: Here we're just creating our own Iterable implementation. The JavaType is available, if we wanted to do
+ // more fine-tuned introspection to determine what specific type of Iterable to instantiate. There are several
+ // Java-Scala conversions available; we just want a thin facade implementation of the Java interface that simply
+ // calls the associated Scala collection methods. Shouldn't really be any speed degradation here.
val list = new ListBuffer[Object]()
val collection = asJavaList(list)
javaCollectionDeserializer.deserialize(jp, ctxt, collection)
+ // mutable.List and immutable.List are not compatible; if the requested type is immutable, just return the
+ // mutable ListBuffer as a immutable Iterable List.
if (isImmutableTypeRequested) {
list.toList
} else {
@@ -8,20 +8,28 @@ import collection.JavaConversions._
import java.lang.reflect.Constructor
import collection.mutable.{HashMap}
+/**
+ * ScalaMapDeserializer deserializes json maps into Scala Maps.
+ *
+ * Note: See ScalaListDeserializer for implementation details. I've made some assumptions about the implementation
+ * of the Java deserializers, simply wrapping them with my own implementations, wrapping them with scala based
+ * collections.
+ */
class ScalaMapDeserializer(mapType: JavaType,
keyDeser: KeyDeserializer,
valueDeser: JsonDeserializer[Object],
valueTypeDeser: TypeDeserializer) extends JsonDeserializer[collection.Map[Object, Object]] {
- // TODO: the Java MapDeserializer uses this to build a map instance, but we're hoping to build one ourselves.
val defaultConstructor: Constructor[java.util.Map[Object, Object]] = null
val javaMapDeserializer = new MapDeserializer(mapType, defaultConstructor, keyDeser, valueDeser, valueTypeDeser)
def deserialize(jp: JsonParser, ctxt: DeserializationContext) : collection.Map[Object, Object] = {
-
+ // Again, see ScalaListDeserializer for more info about this implementation.
val map = new HashMap[Object, Object]()
val javaMap = asJavaMap(map)
+
+ // Let the Java deserializer do the real work here - the actual parsing - and make calls to our thin Map facade.
javaMapDeserializer.deserialize(jp, ctxt, javaMap)
if (isImmutableTypeRequested) {
@@ -2,8 +2,11 @@ package com.fasterxml.jackson.module.scala.ser
import org.codehaus.jackson.map._
import org.codehaus.jackson._
-import ser.{ContainerSerializerBase, CustomSerializerFactory}
+/**
+ * The implementation is taken from the code written by Greg Zoller, found here:
+ * http://jira.codehaus.org/browse/JACKSON-211
+ */
class ScalaEnumerationSerializer extends JsonSerializer[scala.Enumeration$Val] {
override def serialize(value: scala.Enumeration$Val, jgen: JsonGenerator, provider: SerializerProvider) = {
val parentEnum = value.asInstanceOf[AnyRef].getClass.getSuperclass.getDeclaredFields.find( f => f.getName == "$outer" ).get
@@ -2,8 +2,12 @@ package com.fasterxml.jackson.module.scala.ser
import org.codehaus.jackson.map._
import org.codehaus.jackson._
-import ser.{ContainerSerializerBase, CustomSerializerFactory}
+import ser.ContainerSerializerBase
+/**
+ * The implementation is taken from the code written by Greg Zoller, found here:
+ * http://jira.codehaus.org/browse/JACKSON-211
+ */
class ScalaIterableSerializer extends ContainerSerializerBase[Iterable[Any]](classOf[Iterable[Any]]) {
override def serialize(value:Iterable[Any], jgen:JsonGenerator, provider:SerializerProvider) {
jgen.writeStartArray();
@@ -2,9 +2,13 @@ package com.fasterxml.jackson.module.scala.ser
import org.codehaus.jackson.map._
import org.codehaus.jackson._
-import ser.{ContainerSerializerBase, CustomSerializerFactory}
+import ser.ContainerSerializerBase
import collection.Map
+/**
+ * The implementation is taken from the code written by Greg Zoller, found here:
+ * http://jira.codehaus.org/browse/JACKSON-211
+ */
class ScalaMapSerializer extends ContainerSerializerBase[Map[String,Any]](classOf[Map[String,Any]]) {
override def serialize(value:Map[String,Any], jgen:JsonGenerator, provider:SerializerProvider) {
jgen.writeStartObject();
@@ -2,8 +2,11 @@ package com.fasterxml.jackson.module.scala.ser
import org.codehaus.jackson.map._
import org.codehaus.jackson._
-import ser.{ContainerSerializerBase, CustomSerializerFactory}
+/**
+ * The implementation is taken from the code written by Greg Zoller, found here:
+ * http://jira.codehaus.org/browse/JACKSON-211
+ */
class ScalaOptionSerializer extends JsonSerializer[Option[Any]] {
override def serialize(value:Option[Any], jgen:JsonGenerator, provider:SerializerProvider) {
jgen.writeStartObject();
@@ -3,6 +3,10 @@ package com.fasterxml.jackson.module.scala.ser
import org.codehaus.jackson.map._
import org.codehaus.jackson.`type`.JavaType
+/**
+ * The implementation of these Scala*Serializers is taken from the code written by Greg Zoller, found here:
+ * http://jira.codehaus.org/browse/JACKSON-211
+ */
class ScalaSerializers extends Serializers {
override def findSerializer(config: SerializationConfig, javaType: JavaType, beanDescription: BeanDescription, property: BeanProperty) = {
@@ -20,4 +24,4 @@ class ScalaSerializers extends Serializers {
null
}
}
-}
+}
@@ -4,7 +4,6 @@ import org.scalatest.matchers.ShouldMatchers
import org.scalatest.FlatSpec
import org.codehaus.jackson.map.ObjectMapper
import java.io.StringWriter
-import reflect.BeanProperty
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith

0 comments on commit 7cef47c

Please sign in to comment.