Play Framework - Как проанализировать массив JSON с возможными значениями NULL - PullRequest
0 голосов
/ 06 декабря 2018

У меня следующий класс дел

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

Кажется, я не могу писать операции чтения для этого класса в основном из-за типа results.Если я попробую без варианта.то есть 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

в принципе, я не могу найти более простой способобрабатывать unmarsheling JSON до Iterable[Array[Option[String]]].должен быть один.

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Circe - одна из самых популярных библиотек JSON в Scala

. Вот более элегантное решение с использованием 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 очень хорошо разбирается, и он автоматически кодирует / декодирует почти все типы объектов Scala.Поэтому нам не нужно нигде определять неявные.Просто импортируйте io.circe.generic.auto._ в свой класс Scala и все.

Вот хороший справочный блог для анализа JSON с использованием Circe

Надеюсь, это поможет!!

0 голосов
/ 06 декабря 2018

В этом случае вы можете реализовать 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)
  }
}

Надеюсь, этопомогает!

...