[Play 2.1 Scala] Json serializing Option[] None

2,306 views
Skip to first unread message

Volker Hatz

unread,
Mar 18, 2013, 8:35:44 AM3/18/13
to play-fr...@googlegroups.com
I am having cases classes with a lot of Option[] values. When I serialize these classes all None values get mapped to "somename":null. This results in unnecessary big Json structurer.

An example is already in the docs

val zombie = Creature("zombie", true, 100.0F, "sh...@dead.com", ("ain", 2), List(gizmo), None)
val zombiejs = Json.toJson(zombie)
zombiejs: play.api.libs.json.JsValue = {"name":"zombie","isDead":true,"weight":100.0,"email":"sh...@dead.com","favorites":{"string":"ain","number":2},"friends":[{"name":"gremlins","isDead":false,"weight":1.0,"email":"gi...@midnight.com","favorites":{"string":"alpha","number":85},"friends":[],"social":"@gizmo"}],"social":null

As you see, the social field (last in the Creature case class), which is None, results in a "social":null output.

Is there any way to suppress that (Jackson object mapper has an option for that)? I don't want to see the nulls ... following Pascals post in a different threadI advise not to use null for a missing field in JSON. null is a valid value in JSON (mapped to JsNull in Play).

Pascal Voitot Dev

unread,
Mar 18, 2013, 8:46:47 AM3/18/13
to play-fr...@googlegroups.com
Do you use Json macro or manual Writes?



--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Volker Hatz

unread,
Mar 18, 2013, 9:06:33 AM3/18/13
to play-fr...@googlegroups.com
This is a code example:

  implicit val writeResponse = (
    (__ \ 'a).write[Option[String]] and
    (__ \ 'b).write[Option[Boolean]] and
    (__ \ 'c).write[Option[Seq[DClass]]]
    )(unlift(EClass.unapply))

Then I use Json.toJson(EClass(b = Some(true))

This has two JsNull for a and c. Doing an e.g. stringify then also prints those out.

Am Montag, 18. März 2013 13:46:47 UTC+1 schrieb Pascal:
Do you use Json macro or manual Writes?
On Mon, Mar 18, 2013 at 1:35 PM, Volker Hatz <volke...@gmail.com> wrote:
I am having cases classes with a lot of Option[] values. When I serialize these classes all None values get mapped to "somename":null. This results in unnecessary big Json structurer.

An example is already in the docs

val zombie = Creature("zombie", true, 100.0F, "sh...@dead.com", ("ain", 2), List(gizmo), None)
val zombiejs = Json.toJson(zombie)
zombiejs: play.api.libs.json.JsValue = {"name":"zombie","isDead":true,"weight":100.0,"email":"shaun@dead.com","favorites":{"string":"ain","number":2},"friends":[{"name":"gremlins","isDead":false,"weight":1.0,"email":"gi...@midnight.com","favorites":{"string":"alpha","number":85},"friends":[],"social":"@gizmo"}],"social":null

Pascal Voitot Dev

unread,
Mar 18, 2013, 9:13:32 AM3/18/13
to play-fr...@googlegroups.com
with the macros, it would have worked ;)

but your behavior is normal actually

(__ \ 'a).write[Option[String]](implicit w: Writes[Option[String]]) uses the pure Writes[Option[T]] which must write something (it can't write nothing) so it writes JsNull.

That's why we provide a field writes:

(__ \ 'a).writeNullable[String] which doesn't write the field if None
 
and
(__ \ 'a).readNullable[String] which read missing field or null field to None

Pascal

Volker Hatz

unread,
Mar 18, 2013, 9:25:19 AM3/18/13
to play-fr...@googlegroups.com
Actually I use them on the Read side.

When I used writeNullable I get a compile time error.

 case class EClass( a: Option[String] = None,
                       b: Option[Boolean] = None,
                       c: Option[String] = None)

 implicit val writeE = (
     (__ \ 'a).writeNullable[Option[String]] and
     (__ \ 'b).writeNullable[Option[Boolean]] and
     (__ \ 'c).writeNullable[Option[String]]
     )(unlift(EClass.unapply))

overloaded method value apply with alternatives:
[error]   [B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)](f: B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply) => (Option[Option[String]], Option[Option[Boolean]], Option[Option[String]]))(implicit fu: play.api.libs.functional.ContravariantFunctor[play.api.libs.json.OWrites])play.api.libs.json.OWrites[B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)] <and>
[error]   [B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)](f: (Option[Option[String]], Option[Option[Boolean]], Option[Option[String]]) => B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply))(implicit fu: play.api.libs.functional.Functor[play.api.libs.json.OWrites])play.api.libs.json.OWrites[B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)]
[error]  cannot be applied to (EClass => (Option[String], Option[Boolean], Option[String]))
[error]      (__ \ 'b).writeNullable[Option[Boolean]] and
[error]                                               ^
[error] one error found

Pascal Voitot Dev

unread,
Mar 18, 2013, 9:29:09 AM3/18/13
to play-fr...@googlegroups.com

Not (__ \ 'a).writeNullable[Option[String]]
but
(__ \ 'a).writeNullable[String]

This error is a bit weird but actually it's very simple:

It just says:"I can't match EClass.unapply with the combined Reads you give to me" and the signature of your combined Read appears in bold hereafter

overloaded method value apply with alternatives:
[error]   [B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)](f: B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply) => (Option[Option[String]], Option[Option[Boolean]], Option[Option[String]]))(implicit fu: play.api.libs.functional.ContravariantFunctor[play.api.libs.json.OWrites])play.api.libs.json.OWrites[B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)] <and>
[error]   [B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)](f: (Option[Option[String]], Option[Option[Boolean]], Option[Option[String]]) => B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply))(implicit fu: play.api.libs.functional.Functor[play.api.libs.json.OWrites])play.api.libs.json.OWrites[B(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)(in method apply)]

Volker Hatz

unread,
Mar 18, 2013, 9:34:50 AM3/18/13
to play-fr...@googlegroups.com
Thanks Pascal! It works, you saved my day.
Reply all
Reply to author
Forward
0 new messages