From 2a30769cce1dbc2cfa55860e66be82f6665e81bf Mon Sep 17 00:00:00 2001 From: Christopher Currie Date: Mon, 1 Oct 2012 20:10:56 -0700 Subject: [PATCH] A real fix for #32 --- .../scala/ser/OptionSerializerModule.scala | 50 ++++++++++++++++--- .../jackson/module/scala/JacksonTest.scala | 2 +- .../scala/ser/OptionSerializerTest.scala | 12 +++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala index 86fcaf111..68f89df1e 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala @@ -1,22 +1,53 @@ package com.fasterxml.jackson.module.scala.ser -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.{BeanDescription, JavaType, JsonSerializer, SerializationConfig, SerializerProvider}; -import com.fasterxml.jackson.databind.ser.Serializers +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.{BeanDescription, JavaType, JsonSerializer, SerializationConfig, SerializerProvider} +import com.fasterxml.jackson.databind.ser.{BeanPropertyWriter, BeanSerializerModifier, Serializers} import com.fasterxml.jackson.module.scala.modifiers.OptionTypeModifierModule +import scala.collection.JavaConverters._ +import java.{util => ju} private class OptionSerializer extends JsonSerializer[Option[_]] { def serialize(value: Option[_], jgen: JsonGenerator, provider: SerializerProvider) { value match { - case Some(v) => jgen.writeObject(v) - case None => jgen.writeNull() + case Some(v) => provider.defaultSerializeValue(v, jgen) + case None => provider.defaultSerializeNull(jgen) } } override def isEmpty(value: Option[_]): Boolean = value.isEmpty } +private class OptionPropertyWriter(delegate: BeanPropertyWriter) extends BeanPropertyWriter(delegate) +{ + override def serializeAsField(bean: AnyRef, jgen: JsonGenerator, prov: SerializerProvider) { + (get(bean), _nullSerializer) match { + // value is None, which we'll serialize as null, but there's no + // null-serializer, which means it should be suppressed + case (None, null) => return + case _ => super.serializeAsField(bean, jgen, prov) + } + } +} + +private object OptionBeanSerializerModifier extends BeanSerializerModifier { + + override def changeProperties(config: SerializationConfig, + beanDesc: BeanDescription, + beanProperties: ju.List[BeanPropertyWriter]): ju.List[BeanPropertyWriter] = { + + beanProperties.asScala.transform { w => + if (classOf[Option[_]].isAssignableFrom(w.getPropertyType)) + new OptionPropertyWriter(w) + else + w + }.asJava + + } + +} + private object OptionSerializerResolver extends Serializers.Base { private val OPTION = classOf[Option[_]] @@ -27,6 +58,11 @@ private object OptionSerializerResolver extends Serializers.Base { } + + trait OptionSerializerModule extends OptionTypeModifierModule { - this += (_ addSerializers OptionSerializerResolver) -} \ No newline at end of file + this += { ctx => + ctx addSerializers OptionSerializerResolver + ctx addBeanSerializerModifier OptionBeanSerializerModifier + } +} diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/JacksonTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/JacksonTest.scala index 641b63500..f5c01d7dc 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/JacksonTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/JacksonTest.scala @@ -6,7 +6,7 @@ trait JacksonTest { def module: Module - val mapper = { + def mapper = { val result = new ObjectMapper result.registerModule(module) result diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerTest.scala index de3f276e8..8488c46ec 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerTest.scala @@ -6,6 +6,7 @@ import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.annotation.{JsonProperty, JsonInclude} +import annotation.target.getter class NonEmptyOptions { @@ -62,4 +63,15 @@ class OptionSerializerTest extends SerializerTest with FlatSpec with ShouldMatch serialize(new NonEmptyOptions) should be ("""{"some":1}""") } + it should "honor JsonInclude.Include.NON_NULL" in { + val nonNullMapper = mapper + nonNullMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + nonNullMapper.writeValueAsString(new NonNullOption()) should be ("{}") + } + } + +class NonNullOption { + @JsonProperty var foo: Option[String] = None +} +