Skip to content

Commit

Permalink
Test and fix for #103
Browse files Browse the repository at this point in the history
  • Loading branch information
christophercurrie committed Oct 20, 2013
1 parent ee9ecf0 commit 640fb34
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,42 +1,74 @@
package com.fasterxml.jackson.module.scala.ser
package com.fasterxml.jackson
package module.scala
package ser

import util.Implicits._
import modifiers.OptionTypeModifierModule

import core.JsonGenerator
import databind._
import jsontype.TypeSerializer
import jsonschema.{JsonSchema, SchemaAware}
import ser.{ContextualSerializer, BeanPropertyWriter, BeanSerializerModifier, Serializers}
import ser.std.StdSerializer
import `type`.CollectionLikeType
import jsonFormatVisitors.JsonFormatVisitorWrapper

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.databind.ser.{ContextualSerializer, BeanPropertyWriter, BeanSerializerModifier, Serializers}
import com.fasterxml.jackson.module.scala.modifiers.OptionTypeModifierModule
import scala.collection.JavaConverters._
import java.{util => ju}
import com.fasterxml.jackson.databind.`type`.CollectionLikeType
import com.fasterxml.jackson.databind.jsontype.TypeSerializer
import com.fasterxml.jackson.databind.jsonschema.{JsonSchema, SchemaAware}
import java.lang.reflect.Type
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.fasterxml.jackson.databind.node.ObjectNode
import java.{util => ju}

import scala.Some
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper
import scala.collection.JavaConverters._

private class OptionSerializer(valueSerializer: Option[JsonSerializer[AnyRef]], javaType: JavaType, beanProperty: Option[BeanProperty] = None)
private class OptionSerializer(elementType: Option[JavaType],
valueTypeSerializer: Option[TypeSerializer],
beanProperty: Option[BeanProperty],
elementSerializer: Option[JsonSerializer[AnyRef]])
extends StdSerializer[Option[_]](classOf[Option[_]])
with ContextualSerializer
with SchemaAware
{

def serialize(value: Option[_], jgen: JsonGenerator, provider: SerializerProvider) {
(value, valueSerializer) match {
(value, elementSerializer) match {
case (Some(v: AnyRef), Some(vs)) => vs.serialize(v, jgen, provider)
case (Some(v), _) => provider.defaultSerializeValue(v, jgen)
case (None, _) => provider.defaultSerializeNull(jgen)
}
}

def createContextual(prov: SerializerProvider, property: BeanProperty): JsonSerializer[_] = {
val newValueSerializer = valueSerializer.orElse {
val containedType = javaType.containedType(0)
if (!containedType.getRawClass.equals(classOf[Object]))
Option(prov.findValueSerializer(javaType.containedType(0), property))
else None
// Based on the version in AsArraySerializerBase
val typeSer = valueTypeSerializer.optMap(_.forProperty(property))
var ser: Option[JsonSerializer[_]] =
Option(property).flatMap { p =>
Option(p.getMember).flatMap { m =>
Option(prov.getAnnotationIntrospector.findContentSerializer(m)).map { serDef =>
prov.serializerInstance(m, serDef)
}
}
} orElse elementSerializer
ser = Option(findConvertingContentSerializer(prov, property, ser.orNull))
if (ser.isEmpty) {
if (elementType.isDefined) {
if (hasContentTypeAnnotation(prov, property)) {
ser = Option(prov.findValueSerializer(elementType.get, property))
}
}
}
else {
ser = Option(prov.handleSecondaryContextualization(ser.get, property))
}
if ((ser != elementSerializer) || (property != beanProperty.orNull) || (valueTypeSerializer != typeSer))
new OptionSerializer(elementType, typeSer, Option(property), ser.asInstanceOf[Option[JsonSerializer[AnyRef]]])
else this
}

def hasContentTypeAnnotation(provider: SerializerProvider, property: BeanProperty) = {
Option(property).exists { p =>
Option(provider.getAnnotationIntrospector).exists { intr =>
Option(intr.findSerializationContentType(p.getMember, p.getType)).isDefined
}
}
new OptionSerializer(newValueSerializer, javaType, Option(property))
}

override def isEmpty(value: Option[_]): Boolean = value.isEmpty
Expand All @@ -45,10 +77,10 @@ private class OptionSerializer(valueSerializer: Option[JsonSerializer[AnyRef]],
getSchema(provider, typeHint, isOptional = true)

override def getSchema(provider: SerializerProvider, typeHint: Type, isOptional: Boolean): JsonNode = {
val contentSerializer = valueSerializer.getOrElse {
val contentSerializer = elementSerializer.getOrElse {
val javaType = provider.constructType(typeHint)
val componentType = javaType.containedType(0)
provider.findValueSerializer(componentType, beanProperty.orNull)
provider.findTypedValueSerializer(componentType, true, beanProperty.orNull)
}
contentSerializer match {
case cs: SchemaAware => cs.getSchema(provider, contentSerializer.handledType(), isOptional)
Expand All @@ -57,7 +89,9 @@ private class OptionSerializer(valueSerializer: Option[JsonSerializer[AnyRef]],
}

override def acceptJsonFormatVisitor(wrapper: JsonFormatVisitorWrapper, javaType: JavaType) {
valueSerializer.map{_.acceptJsonFormatVisitor(wrapper, javaType.containedType(0))}
val containedType = javaType.containedType(0)
val ser = elementSerializer.getOrElse(wrapper.getProvider.findTypedValueSerializer(containedType, true, beanProperty.orNull))
ser.acceptJsonFormatVisitor(wrapper, containedType)
}
}

Expand Down Expand Up @@ -94,15 +128,15 @@ private object OptionSerializerResolver extends Serializers.Base {

private val OPTION = classOf[Option[_]]

override def findCollectionLikeSerializer(confg: SerializationConfig,
override def findCollectionLikeSerializer(config: SerializationConfig,
`type`: CollectionLikeType,
beanDesc: BeanDescription,
elementTypeSerializer: TypeSerializer ,
elementValueSerializer: JsonSerializer[AnyRef]
): JsonSerializer[_] =

if (!OPTION.isAssignableFrom(`type`.getRawClass)) null
else new OptionSerializer(Option(elementValueSerializer), `type`)
else new OptionSerializer(Option(`type`.containedType(0)), Option(elementTypeSerializer), None, Option(elementValueSerializer))
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,31 @@ import com.fasterxml.jackson.annotation.{JsonProperty, JsonInclude}
import annotation.target.getter
import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper
import com.fasterxml.jackson.module.scala.experimental.RequiredPropertiesSchemaModule
import com.fasterxml.jackson.databind.JsonNode

class NonEmptyOptions {
object OptionSerializerTest
{
class NonEmptyOptions {

//@JsonProperty
@(JsonInclude)(JsonInclude.Include.NON_EMPTY)
val none = None
//@JsonProperty
@(JsonInclude)(JsonInclude.Include.NON_EMPTY)
val none = None

//@JsonProperty
@(JsonInclude @getter)(JsonInclude.Include.NON_EMPTY)
val some = Some(1)
//@JsonProperty
@(JsonInclude @getter)(JsonInclude.Include.NON_EMPTY)
val some = Some(1)

}
}

case class OptionSchema(stringValue: Option[String])
case class OptionSchema(stringValue: Option[String])

case class MixedOptionSchema(@JsonProperty(required=true) nonOptionValue: String, stringValue: Option[String])
case class MixedOptionSchema(@JsonProperty(required=true) nonOptionValue: String, stringValue: Option[String])
case class WrapperOfOptionOfJsonNode(jsonNode: Option[JsonNode])
}

/**
* Undocumented class.
*/
@RunWith(classOf[JUnitRunner])
class OptionSerializerTest extends SerializerTest with FlatSpec with ShouldMatchers {
import OptionSerializerTest._

lazy val module = DefaultScalaModule

Expand Down Expand Up @@ -113,6 +116,16 @@ class OptionSerializerTest extends SerializerTest with FlatSpec with ShouldMatch
schemaString should be === ("""{"type":"object","properties":{"stringValue":{"type":"string"},"nonOptionValue":{"type":"string","required":true}}}""")
}

it should "serialize contained JsonNode correctly" in {
val json: String = """{"prop":"value"}"""
val tree: JsonNode = mapper.readTree(json)
val wrapperOfOptionOfJsonNode = WrapperOfOptionOfJsonNode(Some(tree))

val actualJson: String = mapper.writeValueAsString(wrapperOfOptionOfJsonNode)

actualJson should be === """{"jsonNode":{"prop":"value"}}"""
}

}

class NonNullOption {
Expand Down

0 comments on commit 640fb34

Please sign in to comment.