2015-12-03 70 views
3

我正在使用一个API,它在响应中的多个图层上公开一个对象。例如,对于一些反应,我们得到一个:播放Json递归读取

{ 
    "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],在那里我的阅读电话预计为JsArray

这是否有一个很好的方法?

+1

它看起来像你试图读错误'作为一个数组,但你举例来说,它是一个对象。 – pedrofurla

+0

@healsjnr你张贴无效的JSON这是链接,看到JSON数据http://jsonviewer.stack.hu/ – Amitsharma

+0

@pedrofurla是的,这就是我想解决的。我希望能够通过执行'(JsArray(__ \\“error”)),将'Seq [JsValue]'转换为'JsArray''',但没有快乐。 – healsjnr

回答

0

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

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

应该更接近你想要什么。 (__ \\ "error")给你的JsValues一个Seqmap做了每一个JsValuereadJsValue转换为ErrorMessage,你传递给ErrorResponse构造所产生的Seq[ErrorMessage]

+0

不幸的是,这种类型与Play Json不太一样。特别是'(__ \\“错误”)'在这种情况下实际上是一个JsPath。在传递给Reads.read方法之前,它不会被评估为Seq [JsValue]。 – healsjnr

0

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

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) 
) 

基本上你需要定义读取您使用作了明确规定。在读取中,您可以使用递归搜索返回Seq[JsValue],然后创建一个JsArray,它可以像正常一样进行验证。

这很好,如果我们不必定义一个单独的Reads [T],那将会很好。