【问题标题】:Providing implicit value for singletons in Play Json library在 Play Json 库中为单例提供隐式值
【发布时间】:2015-06-16 02:19:48
【问题描述】:

我有以下配置:

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,因为它需要应用和取消应用功能。我该怎么办?

编辑1:

我能想到这样的事情:

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

【问题讨论】:

    标签: json scala playframework scala-macros


    【解决方案1】:

    使用函数式 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]
    

    我发现这比手动实现readswrites 方法更清晰,主要是因为它突出了编码和解码之间的对称性。不过,这只是口味问题。

    【讨论】:

    • __ 真的是两个下划线(要记住这么多符号:))?对称性在哪里? (这些天试着学习看起来“功能性”,你推荐manning.com/bjarnason还是更好的?)
    • 是的,真的是__。不喜欢的可以写JsPath。我也对运算符重的库持怀疑态度,但 Play JSON 只有几个运算符,我认为它们很合理。
    【解决方案2】:

    为此,我应该像这样定义一个隐式对象:

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

    【讨论】:

      猜你喜欢
      • 2016-08-25
      • 1970-01-01
      • 2019-01-03
      • 2012-09-27
      • 1970-01-01
      • 2017-03-16
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多