播放框架-如何使用可能的null值解析json数组

时间:2018-12-06 03:45:28

标签: playframework playframework-2.6 play-json

我有以下案例课

case class DataResponse(results: Iterable[Array[Option[String]]], exceptionMessage: Option[String])

主要由于results的类型,我似乎无法为此类编写Reads。如果我尝试没有选择。即Iterable[Array[String]]可以工作,但是当json字符串具有空值时,它会崩溃。

implicit val DataReads2 = ( (JsPath \ “results”).read[Iterable[Array[Option[String]]]] and //compile error (JsPath \ “exceptionMessage”).readNullable[String] )(DataResponse.apply _)

编译错误:

No Json deserializer found for type Iterable[Array[Option[String]]]. Try to implement an implicit Reads or Format for this type.

如果我尝试实现隐式读取,则会得到:

implicit val itrOptReads = Json.reads[Iterable[Array[Option[String]]]]

No apply function found for scala.collection.Iterable

基本上,我似乎找不到更简单的方法来处理将json编组为Iterable[Array[Option[String]]]的方法。应该有一个。

2 个答案:

答案 0 :(得分:1)

在这种情况下,您可以实现CustomIterableFormat。这是示例:

object CustomIterableFormat extends Reads[Iterable[Array[Option[String]]]] with Writes[Iterable[Array[Option[String]]]] {
  implicit val optionalStringArrayFormat = CustomArrayFormat
  override def reads(json: JsValue): JsResult[Iterable[Array[Option[String]]]] = {
    Try(json.as[Iterable[JsValue]].map { someJson =>
      someJson.as[Array[Option[String]]]
    }).map(JsSuccess(_)).getOrElse(JsError(s"invalid sequence: $json"))
  }

  override def writes(o: Iterable[Array[Option[String]]]): JsValue = {
    Json.toJson(o)
  }
}

object CustomArrayFormat extends Reads[Array[Option[String]]] with Writes[Array[Option[String]]] {
  override def reads(json: JsValue): JsResult[Array[Option[String]]] = {
    Try(json.as[Array[JsValue]].map {
      case JsNull          => None
      case JsString(value) => Some(value)
    }).map(JsSuccess(_)).getOrElse(JsError(s"invalid sequence: $json"))
  }

  override def writes(o: Array[Option[String]]): JsValue = {
    Json.toJson(o)
  }
}

然后将CustomIterableFormat导入您的伴随对象中

case class DataResponse(results: Iterable[Array[Option[String]]], exceptionMessage: Option[String])

object DataResponse {
  implicit val resultsFormat = CustomIterableFormat

  implicit val DataReads2 = (
    (JsPath \ "results").read[Iterable[Array[Option[String]]]] and
      (JsPath \ "exceptionMessage").readNullable[String]
  )(DataResponse.apply _)

}

这是一个简单的工作示例:

object TestDataResponseParsing {
  def main(args: Array[String]): Unit = {

    val jsonStr = """{"results":[[null,"testing"]],"exceptionMessage":null}"""
    val parsedFromJson = Json.parse(jsonStr).as[DataResponse]
    println(parsedFromJson)
  }
}

希望这会有所帮助!

答案 1 :(得分:1)

Circe是Scala中最受欢迎的JSON解析库之一

这是使用Circe的更优雅的解决方案。

import io.circe.generic.auto._
import io.circe.parser

case class DataResponse(results: Iterable[Array[Option[String]]], exceptionMessage: Option[String])

object DataResponseParsing extends App {

  val jsonStr = """{
                  "results" : [
                      [
                        null,
                        "bar-1"
                      ],
                      [
                         "foo-2",
                         "bar-2"
                       ]
                    ],
                    "exceptionMessage" : null
                  }""".stripMargin

  val result = parser.decode[DataResponse](jsonStr)

  val dataResponse = result match {
    case Right(value) => value
    case Left(error) => throw error
  }
  println(dataResponse)
}

Circe's automatic derivation非常精通,它会自动编码/解码几乎所有类型的Scala对象。因此,我们无需在任何地方定义隐式。只需在您的Scala类中导入io.circe.generic.auto._即可。

Here's一个很好的参考博客,使用Circe

解析JSON。

希望这会有所帮助!