2

我正在尝试使用读取器/组合器来解析包含混合数据类型的数组,但我不确定如何为这样的东西指定读取器。我有一些这样的 JSON:

{
  "stuff": [1, 2, true, null, "false", "hahaha", 5, "8"]
}

我想将所有这些解析为字符串表示,但是当我尝试使用阅读器时,List[String]我得到了解析异常。我想象这样的事情:

 implicit val mixedArrayReader = (
       (__ \ 'not).readNullable[List[JsValueWrapper]].map(opt => opt.map(list =>
             list.map { wrapper : JsValueWrapper =>
                val parsed : String = wrapper match {
                      case b : JsBoolean => if (b.value) "1" else "0"
                      case n : JsNumber  => n.value.toString
                      case s : JsString  => s.value
                      case JsNull        => "null"
                      case u             => u.toString  // unknown
                   }
                parsed
                }
          ))
 )

但是,由于没有阅读器JsValueWrapper,我不确定从这里去哪里。任何帮助是极大的赞赏。

谢谢!

4

2 回答 2

3

从实现一个自定义的 Reads[String] 开始,然后使用Reads.list将其变成 的阅读器List[String],然后像往常一样使用该阅读器。为了不隐藏 Play 的 default ,宁愿显式传递那些特定的 reader,而不是为他们定义隐式 Reads[String]

import play.api.libs.json.Reads

val myReader: Reads[String] = Reads[String](value => JsSuccess(value match {
  case b : JsBoolean => if (b.value) "1" else "0"
  case n : JsNumber  => n.value.toString
  case s : JsString  => s.value
  case JsNull        => "null"
  case u             => u.toString  // unknown
}))

val listReads = Reads.list[String](myReader)

然后,在组合阅读器中,您可以编写如下内容:

implicit val objReader =
  (__ \ 'not).readNullable(listReads)
于 2013-11-12T21:58:55.063 回答
1

thesamet 的解决方案可能是最直接的。我认为如果您使用.readNullable[List[JsValue]],您的解决方案将起作用,JsValue它是所有 Js* 类型的超类型,您永远不需要直接使用的包装器,它的存在只是为了帮助轻松创建 JSON 对象和数组。

您可以使用的另一个功能更强大、更灵活的解决方案(请注意,此解决方案可以更好地处理错误)是:

val anyValueAsStringReader =
  implicitly[Reads[BigDecimal]].map(_.toString) or
  implicitly[Reads[String]] or
  implicitly[Reads[Boolean]].map(if (_) "1" else "0") or
  implicitly[Reads[JsValue]].map(_.toString)

val mixedArrayReader = (__ \ 'not).readNullable(Reads.list(anyValueAsStringReader))
于 2013-11-14T02:04:05.200 回答