json - Play &Json : How to validate an array of integers

标签 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 有效地包装了一个整数数组?

编辑 根据 Travis 的要求,下面是 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 ]
}

最佳答案

您可以使用这个助手。其写法与play.api.libs.json.Reads.list[A](隐式读取: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

关于json - Play &Json : How to validate an array of integers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25291784/

相关文章:

Java 将 JSON 字符串解析为数组或对象列表

scala - Scala 解释器 (REPL) 准确打印什么(使用 Map 和 HashMap 进行演示)?

Scala:隐式、子类化和成员类型

scala - 如何模拟 Scala 单例对象?

json - 编码泛型类型时生命周期参数的数量错误

javascript - 如何使用 JSON 并通过 D3 返回数据

scala - Intellij : Not a valid project ID:

jpa - 在 Play JPA 项目中使用 sbt-native-packager 将自定义文件夹添加到 Docker

javascript - 如何为 JSON API 创建复杂的 javascript 对象

scala - 异常查询,未找到展平