Json隐式读取:类型不匹配?

时间:2014-09-06 16:20:40

标签: scala playframework implicit

我使用Play 2.3.4,并且我已经将一个简单的模型类定义为:

case class User(
  @Id
   id: Int,
   name: String
) extends Model

object User {
  def find() = { /* some code here */}
  implicit object UserFormat extends Format[User] {
    def reads(json: JsValue) = User(
      (json \ "id").as[Int],
      (json \ "name").as[String]
    )

    def writes(user: User) = JsObject(Seq("id" -> id, "name" -> name))
  }
}

这很简单。但是我收到了编译错误:

Error:(31, -1) Play 2 Compiler: 
 /Users/asheshambasta/code/finit/app/models/users/User.scala:31: type mismatch;
  found   : models.devices.User
  required: play.api.libs.json.JsResult[models.users.User]

我做错了什么?

1 个答案:

答案 0 :(得分:2)

上面的代码有几个问题。您收到的编译错误是因为reads(json: JsValue)应该返回JsResult不是模型。这是因为您在定义Reads时需要考虑失败。 idname也需要在user.iduser.namewrites。这将编译:

object User {

    implicit object UserFormat extends Format[User] {
        def reads(json: JsValue) = JsSuccess(User(
            (json \ "id").as[Int],
            (json \ "name").as[String]
        ))

        def writes(user: User) = Json.obj("id" -> user.id, "name" -> user.name)
    }
}

但是,如果JSON中存在错误,则会抛出异常,因为as[T]不安全。

scala> val testJs = Json.parse("""{"id":"2", "name": "test"}""")
testJs: play.api.libs.json.JsValue = {"id":"2","name":"test"}

scala> testJs.validate[User]
play.api.libs.json.JsResultException: JsResultException(errors:List((,List(ValidationError(error.expected.jsnumber,WrappedArray())))))

以简单对象的方式定义Reads几乎总是不值得的,并且使用JSON组合器可以更好地完成。

object User {
    implicit val reads: Reads[User] = (
        (__ \ "id").read[Int] and 
        (__ \ "name").read[String]
    )

    implicit val writes: Writes[User] = (
        (__ \ "id").write[Int] and 
        (__ \ "name").write[String]
    )    
}

JSON组合器不会像第一段代码那样抛出异常,并且在验证时会将所有错误累积到JsResult中。在这样的简单情况下,JSON开始会更好:

object User {
    implicit val format: Format[User] = Json.format[User]   
}

还有Json.reads[T]Json.writes[T]个宏,以防您需要自定义Reads而不是Writes或其他方式。