Play& Json:如何验证整数数组

时间:2014-08-13 16:46:40

标签: json scala playframework

以下验证程序检查传入的JSON是否正确:

val validateAccount = (
  ((__ \ 'id).json.pickBranch(Reads.of[JsString] <~ objectId) orEmpty) ~
  ((__ \ 'openingTime).json.pickBranch(Reads.of[JsString] <~ utcDateTime) orEmpty) ~
  ((__ \ 'roles).json.pickBranch(Reads.of[JsArray]) orEmpty) ~
  ((__ \ 'permissions).json.pickBranch(Reads.of[JsArray]) orEmpty)
).reduce

roles以及permissions应该是一个整数数组...那么如何验证JsArray是否有效地包装整数数组?

修改 根据特拉维斯的要求,下面是orEmpty ...

的实施
implicit class ReadsExtensions(val reads: Reads[JsObject]) extends AnyVal {

  import play.api.libs.functional.syntax._

  /**
    * Returns either a successful `Reads` or an empty object.
    * @return Either a successful `Reads` or an empty object.
    */
  def orEmpty = reads | __.json.put(Json.obj())

  /**
    * Returns either a successful `Reads` or an empty object if allowed.
    *
    * @param b  A Boolean value indicating  whether or not an empty
    *           object is allowed when a `Reads` fails.
    * @return   Either a successful `Reads` or an empty object if `b`
    *           is `true`.
    */
  def orEmptyIf(b: Boolean) = if (b) orEmpty else reads
}

...这里有一个要验证的JSON示例:

{
  "id": "12d54f56cc456a2967e34a21",
  "openingTime": "2014-08-12T21:10:24Z",
  "roles": [ 0, 1, 3, 4],
  "permissions": [ 0, 1, 2 ,3 ]
}

1 个答案:

答案 0 :(得分:2)

您可以使用此帮助程序。它的写法与play.api.libs.json.Reads.list[A](implicit reads: Reads[A]): Reads[List[A]]类似,但返回JsArray而不是List

  def jsArray[A <: JsValue](implicit r: Reads[A]): Reads[JsArray] = new Reads[JsArray] {

    def reads(json: JsValue) = json.validate[JsArray].flatMap { case JsArray(seq) =>
      type Errors = Seq[(JsPath, Seq[ValidationError])]
      def locate(e: Errors, idx: Int) = e.map { case (p, valerr) => JsPath(idx) ++ p -> valerr }

      seq.zipWithIndex.foldLeft(Right(Vector.empty): Either[Errors, Vector[JsValue]]) {
        case (eith, (jsVal, idx)) => (eith, jsVal.validate[A](r)) match {
          case (Right(vs), JsSuccess(v, _)) => Right(vs :+ v)
          case (Right(_), JsError(e)) => Left(locate(e, idx))
          case (Left(e), _: JsSuccess[_]) => Left(e)
          case (Left(e1), JsError(e2)) => Left(e1 ++ locate(e2, idx))
        }
      }.fold(JsError.apply, { res =>
        JsSuccess(JsArray(res.toSeq))
      })
    }

  }

然后你可以使用它

val validateAccount = (
  ((__ \ 'id).json.pickBranch(Reads.of[JsString] <~ objectId) orEmpty) ~
  ((__ \ 'openingTime).json.pickBranch(Reads.of[JsString] <~ utcDateTime) orEmpty) ~
  ((__ \ 'roles).json.pickBranch(jsArray(Reads.of[JsNumber])) orEmpty) ~
  ((__ \ 'permissions).json.pickBranch(jsArray(Reads.of[JsNumber])) orEmpty)
).reduce