aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@driver.xyz>2018-06-29 17:56:06 -0700
committerJakob Odersky <jakob@odersky.com>2018-07-02 16:28:46 -0700
commitc5c1aa6bc78b6ebc346befe9f4b434401a683a59 (patch)
treefd5a92d7b89825d68496306d81dc7ebd2b2f1981
parent1c358416737f8e7d41d6858000ce07680df7afee (diff)
downloadspray-json-derivation-c5c1aa6bc78b6ebc346befe9f4b434401a683a59.tar.gz
spray-json-derivation-c5c1aa6bc78b6ebc346befe9f4b434401a683a59.tar.bz2
spray-json-derivation-c5c1aa6bc78b6ebc346befe9f4b434401a683a59.zip
Make inclusion of None values as null optional
-rw-r--r--CHANGELOG.md7
-rw-r--r--shared/src/main/scala/DerivedFormats.scala19
-rw-r--r--shared/src/test/scala/OptionFieldTests.scala53
-rw-r--r--shared/src/test/scala/ProductTypeFormatTests.scala17
4 files changed, 74 insertions, 22 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6bdcd86..bf4dbd7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# Version 0.5.0
+
+None values are no longer written to objects by default. This is
+configurable by overriding `printNull` in DerivedFormats.
+
# Version 0.4.7
Upgrade Magnolia from 0.7.1-1 to 0.8.0-1.
@@ -5,7 +10,7 @@
# Version 0.4.6
- Fix a bug in the derivation macro that prevented deriving formats for
- parameterized types. I.e. it is now possible to write derive the following:
+ parameterized types. I.e. it is now possible to derive the following:
```
class A[B](b: B)
implicit def fmt[B: JsonFormat] = jsonFormat[A]
diff --git a/shared/src/main/scala/DerivedFormats.scala b/shared/src/main/scala/DerivedFormats.scala
index 6ea7c4b..ccf48d1 100644
--- a/shared/src/main/scala/DerivedFormats.scala
+++ b/shared/src/main/scala/DerivedFormats.scala
@@ -13,13 +13,24 @@ trait DerivedFormats { self: BasicFormats =>
* method can be overriden to use alternative naming conventions. */
@inline def extractFieldName(paramName: String): String = paramName
+ /** Determines if `None` instances of options should be included in JSON output.
+ *
+ * By default, `None` values are ommitted entirely from resulting JSON
+ * objects. If overridden, they will be included as `null`s instead.
+ *
+ * Note that this has no effect in *reading* option types; undefined or null
+ * values are always converted to `None`. */
+ def printNull: Boolean = false
+
def combine[T](ctx: CaseClass[JsonFormat, T]): JsonFormat[T] =
new JsonFormat[T] {
override def write(value: T): JsValue = {
- val fields: Seq[(String, JsValue)] = ctx.parameters.map { param =>
- extractFieldName(param.label) -> param.typeclass.write(
- param.dereference(value)
- )
+ val fields: Seq[(String, JsValue)] = ctx.parameters.collect {
+ case param
+ if !param.option || param.dereference(value) != None || printNull =>
+ extractFieldName(param.label) -> param.typeclass.write(
+ param.dereference(value)
+ )
}
JsObject(fields: _*)
}
diff --git a/shared/src/test/scala/OptionFieldTests.scala b/shared/src/test/scala/OptionFieldTests.scala
new file mode 100644
index 0000000..8cabf25
--- /dev/null
+++ b/shared/src/test/scala/OptionFieldTests.scala
@@ -0,0 +1,53 @@
+package spray.json
+
+import org.scalatest._
+
+class OptionFieldTests
+ extends FlatSpec
+ with FormatTests {
+
+ case class Opt(x: Option[Int])
+
+ object HideNull extends DerivedJsonProtocol {
+ override def printNull = false
+ implicit val optFmt = jsonFormat[Opt]
+ }
+
+ object ShowNull extends DerivedJsonProtocol {
+ override def printNull = true
+ implicit val optFmt = jsonFormat[Opt]
+ }
+
+
+ "Option fields with some value" should behave like checkRoundtrip(
+ Opt(Some(2)),
+ """{"x":2}"""
+ )(HideNull.optFmt)
+
+ "Option fields with some value (show null)" should behave like checkRoundtrip(
+ Opt(Some(2)),
+ """{"x":2}"""
+ )(ShowNull.optFmt)
+
+ "Option fields with null value" should behave like checkRoundtrip(
+ Opt(None),
+ """{}"""
+ )(HideNull.optFmt)
+
+ "Option fields with null value (show null)" should behave like checkRoundtrip(
+ Opt(None),
+ """{"x":null}"""
+ )(ShowNull.optFmt)
+
+ "Option fields with undefined value" should "deserialize" in {
+ import HideNull._
+ assert("{}".parseJson.convertTo[Opt] == Opt(None))
+ }
+
+ "Option fields with undefined value (show null)" should "deserialize" in {
+ import ShowNull._
+ assert("{}".parseJson.convertTo[Opt] == Opt(None))
+ }
+
+}
+
diff --git a/shared/src/test/scala/ProductTypeFormatTests.scala b/shared/src/test/scala/ProductTypeFormatTests.scala
index 4c979c0..a869ac5 100644
--- a/shared/src/test/scala/ProductTypeFormatTests.scala
+++ b/shared/src/test/scala/ProductTypeFormatTests.scala
@@ -73,23 +73,6 @@ class ProductTypeFormatTests
"""{"h": {"x":true}}"""
)
- case class Opt(x: Option[Int])
- implicit val optFmt = jsonFormat[Opt]
-
- "Option fields with some value" should behave like checkRoundtrip(
- Opt(Some(2)),
- """{"x":2}"""
- )
-
- "Option fields with null value" should behave like checkRoundtrip(
- Opt(None),
- """{"x":null}"""
- )
-
- "Option fields with undefined value" should "deserialize" in {
- assert("{}".parseJson.convertTo[Opt] == Opt(None))
- }
-
case class Typed[T](t: T)
implicit def typed[T: JsonFormat] = jsonFormat[Typed[T]]