Given the following case classes:
case class Mailbox(value: String)
case class Group(objectType: String, mailbox: Mailbox)
I am attempting to find a way to encode a Group object as follows where mailbox
is encoded as a string value, rather than an object:
{
"objectType" : "Group",
"mailbox" : "mailto:[email protected]"
}
With automatic derivation, encoding/decoding both succeed but I end up with a result like the following as would be expected:
{
"objectType" : "Group",
"mailbox" : {
"value" : "mailto:[email protected]"
}
}
I can achieve the result that I want by adding a custom encoder like the following:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
However, then decoding fails with the following:
DecodingFailure(Attempt to decode value on failed cursor, List(DownField(value), DownField(mailbox)))
I've attempted to resolve this by also writing a custom decoder for Mailbox but get the same result. Any guidance on the correct way to approach this situation would be appreciated.
Here is the complete code:
case class Mailbox(value: String)
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
case class Group(objectType: String, mailbox: Mailbox)
object Sandbox {
def main(args: Array[String]): Unit = {
val group: Group = Group("Group", Mailbox("mailto:[email protected]"))
val json: String = group.asJson.spaces2
println(json)
parser.decode[Group](json) match {
case Right(group) => println(group)
case Left(err) => println(err)
}
}
}
Note that this is a derived example, meant only to demonstrate my question.
You can use map
/ contramap
instead to map your type to String and back:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = Encoder.encodeString.contramap[Mailbox](_.value)
implicit val decoder: Decoder[Mailbox] = Decoder.decodeString.map[Mailbox](Mailbox.apply)
}
A documentation describing almost exactly this scenario is at Custom encoders/decoders