如何避免Play Framework Json Reads提供的自动转换,而是获得异常

时间:2014-11-11 02:34:23

标签: json scala playframework playframework-json

如果可以进行投射,

Reads似乎会为我做自动投射。例如,Float - >诠释。例如,如果代码获得如下json,

{
"name": "Jack",
"age": 22.4,
"role": "Coder"
}

类Person的实例的字段年龄为22而不是获得无效的参数异常。如果在这种情况下我确实想要例外,那么最佳解决方案是什么?很多。

case class Person(val name: String, val age: Int, val role: String)

object Person {
implicit val residentReads: Reads[Resident] = (
  (JsPath \ "name").read[String](minLength[String](3)) and
  (JsPath \ "age").read[Int](min(0)) and
  (JsPath \ "role").readNullable[String]
)(Resident.apply _)

...
}

1 个答案:

答案 0 :(得分:4)

查看源代码,我们可以看到原因。与JsNumber匹配的任何值都需要toInt

implicit object IntReads extends Reads[Int] {
    def reads(json: JsValue) = json match {
        case JsNumber(n) => JsSuccess(n.toInt)
        case _ => JsError(Seq(JsPath() -> Seq(ValidationError("error.expected.jsnumber"))))
    }
}

为避免这种情况,我们可以实现一个不会验证非整数的新Reads[Int]

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.api.data.validation._

implicit object WholeIntReads extends Reads[Int] {
    def reads(json: JsValue) = json match {
        case JsNumber(n) if(n.isValidInt) => JsSuccess(n.toInt)
        case _ => JsError(Seq(JsPath() -> Seq(ValidationError("error.expected.jsnumber"))))
    }
}

并像这样使用它:

case class Person(val name: String, val age: Int, val role: String)

object Person {
    implicit val residentReads: Reads[Person] = (
        (JsPath \ "name").read[String](minLength[String](3)) and
        (JsPath \ "age").read[Int](WholeIntReads keepAnd min(0)) and
        (JsPath \ "role").read[String]
    )(Person.apply _)
}

(您的示例代码中存在一些不一致之处,因此我修复了它们以进行此编译。唯一相关的行是age。)

<强>结果:

scala> Json.parse("""{"name": "Jack","age": 22.4,"role": "Coder"}""").validate[Person]
res13: play.api.libs.json.JsResult[Person] = JsError(List((/age,List(ValidationError(error.expected.jsnumber,WrappedArray())))))

scala> Json.parse("""{"name": "Jack","age": 22,"role": "Coder"}""").validate[Person]
res14: play.api.libs.json.JsResult[Person] = JsSuccess(Person(Jack,22,Coder),)

scala> Json.parse("""{"name": "Jack","age": -22,"role": "Coder"}""").validate[Person]
res15: play.api.libs.json.JsResult[Person] = JsError(List((/age,List(ValidationError(error.min,WrappedArray(0))))))

请注意,我使用validate[T]而不是抛出异常,因为这是最佳做法。这将允许ValidationError累积并处理,而不需要任何例外。