繁体   English   中英

播放Json递归读取

[英]Play Json Recursive Reads

我正在努力使用一个API,它在它的响应中暴露多个层的对象。 例如,对于一些回复我们得到回复:

{ 
  "error": { 
    "code": "123", 
    "description": "Description" 
  } 
}

但在其他情况下,它回应:

{
  "data": [
    {
      "message_id": "123",
      "error": {
        "code": "123",
        "description": "Description"
      }
    }
  ]
}

在这两种情况下,错误对象都是相同的,在这两种情况下,我实际上并不关心有效负载的其余部分。 我希望使用\\\\递归JsPath运算符,但是下面的实现失败:

case class ErrorMessage(code: String, description: String)
implicit val errorMessageFormat = Json.format[ErrorMessage]

case class ErrorResponse(errors: Seq[ErrorMessage])
implicit val errorResponseFormat: Format[ErrorResponse] = Format(
  (__ \\ "error").read[Seq[ErrorMessage]].map(ErrorResponse),
  (__ \ "errors").write[Seq[ErrorMessage]].contramap((r: ErrorResponse) => r.errors)
)

这给出了一个错误:

JsError(List((//error,List(ValidationError(List(error.expected.jsarray),WrappedArray())))))

我理解为什么: (__ \\\\ "error")返回一个Seq[JsValue] ,其中我的read调用期待一个JsArray

这有一个很好的方式吗?

由于第一块已经是Seq,因此只需映射内部元素,就像映射单个对象一样。 我对框架不是很熟悉(我自己大多使用Json4s),但你的描述听起来像

ErrorResponse((__ \\ "error").map(_.read[Seq[ErrorMessage]]))

应该更接近你想要的。 (__ \\\\ "error")给你一个Seq of JsValuesmap为每个JsValue做一些事情, read将单个JsValue转换为ErrorMessage ,并将生成的Seq[ErrorMessage]传递给ErrorResponse构造函数。

因此对于任何尝试做类似事情的人来说,下面的工作方式。

val errorResponseReads = Reads[ErrorResponse] { value: JsValue =>
  val errorsJsArray: JsArray = JsArray(value \\ "error")
  errorsJsArray.validate[Seq[ErrorMessage]].map(ErrorResponse)
}

然后格式变为:

implicit val errorResponseFormat: Format[ErrorResponse] = Format(
  errorResponseReads,
  (__ \ "errors").write[Seq[ErrorMessage]].contramap((r: ErrorResponse) => r.errors)
)

基本上,您需要定义明确使用的Read。 在读取中,您可以使用递归搜索返回Seq[JsValue] ,然后创建一个可以正常验证的JsArray

这样可以正常工作,如果我们不必定义单独的Reads [T]那将会很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM