简体   繁体   English

播放:将案例类序列化为json的问题

[英]Play: problems serializing case class to json

I'm implementing a REST API for which, in case of error, I want to send back a Json message like this: 我正在实现一个REST API,如果出现错误,我想发回一条Json消息,如下所示:

{"errors":[
  {"timestamp":"14-Jan-2014 20:00:01","message":"Oops... error 1","code":1500}
  {"timestamp":"14-Jan-2014 20:01:04","message":"Oops... error 2","code":1503}
]}

Here below are my Writes : 以下是我的Writes

import org.joda.time.DateTime
import play.api.libs.json._
import play.api.libs.functional.syntax._

class Error private(
  val timestamp: String,
  val message: String,
  val code: Int
) {
  override def hashCode = (timestamp + message + code).hashCode
}

object Error {

  def apply(message: String, code: Int) =
    new Error(DateTime.now.toString(""), message, code)

  def unapply(error: Error) = {
    if (error eq null) null
    else Some((
      error.timestamp,
      error.message,
      error.code
    ))
  }
}

case class Errors(dummy: String, errors: List[Error])

object Errors {

  val errorWrites: Writes[Error] = (
    (__ \ 'timestamp).write[String] ~
    (__ \ 'message).write[String] ~
    (__ \ 'code).write[Int]
  )(unlift(Error.unapply))

  implicit val errorsWrites: Writes[Errors] = (
    (__ \ 'errors).write[List[Error]](errorWrites)
  )(unlift(Errors.unapply))
}

The code above does not compile and I always get the following error: 上面的代码没有编译,我总是得到以下错误:

[test] $ compile
[info] Compiling 1 Scala source to /home/j3d/Projects/test/target/scala-2.10/classes...
[error] /home/j3d/Projects/test/app/models/Errors.scala:88: overloaded method value write with alternatives:
[error]   (t: List[models.core.Error])(implicit w: play.api.libs.json.Writes[List[models.core.Error]])play.api.libs.json.OWrites[play.api.libs.json.JsValue] <and>
[error]   (implicit w: play.api.libs.json.Writes[List[models.core.Error]])play.api.libs.json.OWrites[List[models.core.Error]]
[error]  cannot be applied to (play.api.libs.json.Writes[models.core.Error])
[error]     (__ \ 'errors).write[List[Error]](errorWrites)
[error]                         ^
[error] one error found
[error] (core/compile:compile) Compilation failed
[error] Total time: 0 s, completed Jan 6, 2014 8:02:30 PM

Am I missing something? 我错过了什么吗?

Well, contramap works for me: 那么,contramap适合我:

object Errors {

  implicit val errorWrites: Writes[Error] = (
    (__ \ 'timestamp).write[String] ~
    (__ \ 'message).write[String] ~
    (__ \ 'code).write[Int]
  )(unlift(Error.unapply))

  val foo: Writes[Errors] =  
    (__ \ 'errors).write[List[Error]].contramap( (e:Errors) => e.errors )

}

Direct approach also works: 直接方法也有效:

implicit val errorsWrites = new Writes[Errors] {
  def writes(e: Errors): JsValue = {
    Json.obj(
        "errors" -> Json.toJson(e.errors)
    )
  }
}

And using Writes apply method: 并使用Writes apply方法:

implicit val errorsWrites2 = Writes[Errors] {(e:Errors) => 
    Json.obj("errors" -> Json.toJson(e.errors))
}

I haven't found the way to make play json functional builder accept just one value. 我还没有找到让json功能构建器只接受一个值的方法。 But I think it is not critical, because above methods all work. 但我认为这并不重要,因为上述方法都有效。

From the comments discussion, if you want to specify Writes[Error] explicitly for Errors, you should do it like this: 从评论讨论中,如果要为Errors明确指定Writes [Error],则应该这样做:

val listErrorWrites: Writes[List[Error]] = Writes { l : List[Error] =>
    Json.arr(l.map(Json.toJson(_)(errorWrites)))
  }

implicit val errorsWrites4: Writes[Errors] = (__ \ 'errors).write[List[Error]](listErrorWrites).contramap((e:Errors) => e.errors)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM