2014-01-06 64 views
0

我實現一個REST API爲此,在錯誤的情況下,我要發送回一個JSON消息是這樣的:播放:問題序列化的情況下類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 

我錯過什麼?

回答

1

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

並採用適用於寫操作的方法:

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

我還沒有找到路讓玩json功能的建設者只接受一個價值。 但我認爲這並不重要,因爲上述方法都可以工作。

從意見的討論,如果要指定寫入[錯誤]明確的錯誤,你應該這樣做是這樣的:

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) 
+0

它的工作原理...謝謝:-)但是,爲什麼必須errorWrites是隱含的?即使使用你的Writes,如果我明確指定errorWrites,我又會得到相同的編譯錯誤... – j3d

+0

我使用隱式errorWrites,因爲它更簡單。您需要指定Writes [List [Error]],而不是寫入[Error]。我的方法既可以使用隱式參數也可以使用顯式參數(爲什麼不應該使用它)。真正的問題是將Writes [List [Error]]轉換爲Writes [Errors],我認爲contramap完美地解決了這個問題。 – vitalii

+0

這不起作用:「implicit val errorsWrites:Writes [Errors] = 93(__ \'errors).write [List [Error]](errorWrites).contramap((e:Errors)=> e.errors) 」。無論如何,我只是保持errorWrites隱式。 Tx再次;-) – j3d