Im dealing with some code outside of my immediate control, where I need to encode an option[Thing] where the case is as per normal if Thing exists, however the None case must return 'false' rather than null. Can this be accomplished easily? I'm looking at the docs but not having much success.
My code looks like this:
case class Thing(name: String)
case class BiggerThing(stuff: String, thing: Option[Thing])
implict val ThingEncodeJson: EncodeJson[Thing] =
EncodeJson(t => ("name" := t.name ) ->: jEmptyObject)
and the equivalent for BiggerThing, and the json needs to look like:
For a Some:
"thing":{"name": "bob"}
For a None:
"thing": false
but at present the None case gives:
"thing":null
How do I get it to return false? Could someone point me in the right direction please?
Cheers
You just need a custom CodecJson
instance for Option[Thing]
:
object Example {
import argonaut._, Argonaut._
case class Thing(name: String)
case class BiggerThing(stuff: String, thing: Option[Thing])
implicit val encodeThingOption: CodecJson[Option[Thing]] =
CodecJson(
(thing: Option[Thing]) => thing.map(_.asJson).getOrElse(jFalse),
json =>
// Adopt the easy approach when parsing, that is, if there's no
// `name` property, assume it was `false` and map it to a `None`.
json.get[Thing]("name").map(Some(_)) ||| DecodeResult.ok(None)
)
implicit val encodeThing: CodecJson[Thing] =
casecodec1(Thing.apply, Thing.unapply)("name")
implicit val encodeBiggerThing: CodecJson[BiggerThing] =
casecodec2(BiggerThing.apply, BiggerThing.unapply)("stuff", "thing")
def main(args: Array[String]): Unit = {
val a = BiggerThing("stuff", Some(Thing("name")))
println(a.asJson.nospaces) // {"stuff":"stuff","thing":{"name":"name"}}
val b = BiggerThing("stuff", None)
println(b.asJson.nospaces) // {"stuff":"stuff","thing":false}
}
}
How to encode a BiggerThing
without a thing
property when thing
is None
. You need a custom EncodeJson[BiggerThing]
instance then:
implicit val decodeBiggerThing: DecodeJson[BiggerThing] =
jdecode2L(BiggerThing.apply)("stuff", "thing")
implicit val encodeBiggerThing: EncodeJson[BiggerThing] =
EncodeJson { biggerThing =>
val thing = biggerThing.thing.map(t => Json("thing" := t))
("stuff" := biggerThing.stuff) ->: thing.getOrElse(jEmptyObject)
}