在Play Json库中为单例提供隐含值

时间:2015-06-16 02:19:49

标签: json scala playframework scala-macros

我有以下配置:

sealed trait Status
case object Edited extends Status
case object NotEdited extends Status

case class Tweet(content:String, status:Status)

我想使用Play Json格式,所以我想我必须有这样的东西(我不想在伴侣对象中这样做):

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]
}

但是编译器抱怨并说:

No implicit format for Tweet available.

它还说我不能使用Edited.type,因为它需要应用和取消应用功能。我该怎么办?

EDIT1:

我可以想到这样的事情:

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")
      }
    ))
  }

但是read部分有问题,编译器抱怨它需要JsonResult而不是Edited.type

2 个答案:

答案 0 :(得分:6)

使用功能API可以非常干净地完成这项工作:

Generator()

我发现这比手动实现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] reads方法更清晰,主要是因为它突出了编码和解码之间的对称性。不过,这是一个品味问题。

答案 1 :(得分:3)

为此,我应该定义一个隐含的对象:

  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)
}