reads - Proporcionar valor implícito para singletons en la biblioteca Play Json
play json reads (2)
Para hacer eso, debería definir un objeto implícito como este:
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)
}
Tengo la siguiente configuración:
sealed trait Status
case object Edited extends Status
case object NotEdited extends Status
case class Tweet(content:String, status:Status)
Quiero usar el formato Play Json, así que supongo que tengo que tener algo como esto (no quiero hacerlo en un objeto complementario):
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]
}
pero el compilador se queja y dice:
No implicit format for Tweet available.
También dice que no puedo usar Edited.type
porque necesita aplicar y quitar funciones. ¿Que debería hacer?
Edit1:
Puedo pensar en algo como esto:
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")
}
))
}
pero la parte de read
tiene un problema, el compilador se queja de que necesita JsonResult no Edited.type
También es posible hacerlo de forma bastante limpia con la API funcional:
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]
Encuentro esto más claro que implementar métodos de reads
y writes
mano, principalmente porque resalta la simetría entre la codificación y la decodificación. Es una cuestión de gusto, sin embargo.