I have following configuration:
sealed trait Status
case object Edited extends Status
case object NotEdited extends Status
case class Tweet(content:String, status:Status)
I want to use Play Json format, so I guess I have to have something like this(I don't want to do it in companion object):
trait JsonImpl{
implicit val TweetFormat = Json.format[Tweet]
implicit val statusFormat = Json.format[Status]
implicit val StatusFormat = Json.format[Edited.type]
implicit val NotEditedFormat = Json.format[NotEdited.type]
}
but compiler complains and says:
No implicit format for Tweet available.
Also it says I cannot use Edited.type
because it needs apply and unapply functions. What should I do?
Edit1:
I can think of something like this:
implicit object StatusFormat extends Format[Status] {
def reads(json: JsValue) =
(json \ "type").get.as[String] match {
case "" => Edited
case _ => UnEdited
}
def writes(stat: Status) = JsObject(Seq(
stat match {
case Edited => "type" -> JsString("Edited")
case NotEdited => "type" -> JsString("UnEdited")
}
))
}
but the read
part has problem, the compiler complains that it needs JsonResult not Edited.type
It's also possible to do this pretty cleanly with the functional API:
import play.api.data.validation.ValidationError
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit val StatusFormat: Format[Status] = Format(
(__ \ 'type).read[String].collect[Status](ValidationError("Unknown status")) {
case "UnEdited" => NotEdited
case "Edited" => Edited
},
(__ \ 'type).write[String].contramap {
case Edited => "Edited"
case NotEdited => "UnEdited"
}
)
implicit val TweetFormat: Format[Tweet] = Json.format[Tweet]
I find this clearer than implementing reads
and writes
methods by hand, mostly because it highlights the symmetry between encoding and decoding. It's a matter of taste, though.
For doing that I should define an implicit object like this:
implicit object StatusFormat extends Format[Status] {
def reads(json: JsValue) =
json match {
case JsString("Edited") => JsSuccess(Edited)
case JsString("NotEdited") => JsSuccess(NotEdited)
case _ => JsError("cannot parse it")
}
def writes(stat: Status) = JsString(stat.toString)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With