播放 JSON JsPath 条件类型

Play JSON JsPath Conditional Types

我收到来自我无法控制的上游服务器的 JSON 响应,需要修改。

JSON 可以采用以下格式

{"data":[["Some_text","boolean",["key_string1","key_string2"]]]}

或者它也可以显示为

{"data":[["Some_text","boolean","key_string2"]]}

或者它可以显示为两者的组合。

{"data":[["Some_text","boolean",["key_string1","key_string2"]],["Some_text","boolean","key_string2"]]}

如果它们不混合,我可以单独为每种格式定义 READS。 但是,鉴于数据可能是混合格式,我无法思考应该如何编写Reads以便在转换之前检查底层类型是字符串还是数组?

是否可以这样说

  (
    (JsPath)(0).read[String] and
    (JsPath)(1).read[Boolean] and
    (JsPath)(2).read( **if type is simple, String OR if type is array, then seq** )
  )(SomeGloriousCaseClass)

如何解决这个反序列化问题?

为了好玩,我实现了一个解决方案。您可能需要稍微调整一下:

private def toSeq(jsValue: JsValue): JsResult[Seq[String]] = {
    jsValue match {
      case JsArray(es:Seq[JsValue]) ⇒ sequence(es.map(e ⇒ toSeq(jsValue))).map(_.flatten)
      case JsString(s) ⇒ JsSuccess(s :: Nil)
      case _ ⇒ JsError("INVALID")
    }
  }

  private def sequence[A](seq:Seq[JsResult[A]]):JsResult[Seq[A]] = {
    seq.foldLeft(JsResult.applicativeJsResult.pure(Seq[A]()))((acc, next) ⇒ for(acc2 ← acc; next2 ← next) yield acc2 :+ next2)
  }

希望对您有所帮助,如果需要,我们很乐意提供进一步的解释。