我正在实现一个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}
]}
以下是我的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))
}
上面的代码无法编译,我总是收到以下错误:
[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
我错过了什么吗?
答案 0 :(得分:2)
嗯,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 )
}
直接方法也有效:
implicit val errorsWrites = new Writes[Errors] {
def writes(e: Errors): JsValue = {
Json.obj(
"errors" -> Json.toJson(e.errors)
)
}
}
使用Writes apply方法:
implicit val errorsWrites2 = Writes[Errors] {(e:Errors) =>
Json.obj("errors" -> Json.toJson(e.errors))
}
我还没有找到让json功能构建器只接受一个值的方法。 但我认为这并不重要,因为上述方法都有效。
从评论讨论中,如果你想为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)