Обработка нулей с помощью json Play - PullRequest
0 голосов
/ 09 ноября 2019

Я пытаюсь проанализировать JSON с нулевыми значениями для некоторых полей, используя библиотеку Play. Существует класс дел, который представляет данные:

case class Id(value: Int) extends AnyVal

case class Name(value: String) extends AnyVal

case class Number(value: Int) extends AnyVal

case class Data(id: Option[Id], name: Option[Name], number: Option[Number])

Вот как в настоящее время работает синтаксический анализ:

def parse(jsValue: JsValue): Try[Seq[Data]] = Try {
    jsValue.as[JsArray].value
      .flatMap { record =>
        val id = Id((record \ "id").as[Int])
        val name = Name((record \ "name").as[String])
        val number = Number((record \ "number").as[Int])

        Some(Data(Some(id), Some(name), Some(number)))
      }
  }

Парсинг с конкретными типами данных не обрабатывает пустые случаи, поэтому эта реализациявозвращает:

Failure(play.api.libs.json.JsResultException: JsResultException(errors:List((,List(JsonValidationError(List(error.expected.jsstring),WrappedArray()))))))

Для таких входных данных:

{
    "id": 1248,
    "default": false,
    "name": null,
    "number": 2
  }

Я хотел бы иметь что-то вроде этого: Seq(Data(Some(Id(1248)), None, Some(Number(2))))

Я собираюсь написатьданные в базу данных, поэтому я не против написать пустые значения для этих полей.

Как я могу обработать нулевые значения для полей в разобранном JSON?

Ответы [ 2 ]

1 голос
/ 11 ноября 2019

Вы можете просто позволить библиотеке play-json сгенерировать Reads для ваших классов дел вместо того, чтобы писать их вручную:

import play.api.libs.json._

object Data {
  implicit val reads: Reads[Data] = {
    // move these into the corresponding companion objects if used elsewhere...
    implicit val idReads = Json.reads[Id]
    implicit val numberReads = Json.reads[Number]
    implicit val nameReads = Json.reads[Name]

    Json.reads[Data]
  }
}

def parse(jsValue: JsValue): Try[Seq[Data]] = Json.fromJson[Seq[Data]](jsValue).toTry

Таким образом, ваш код будет работать, даже если вы измените аргументыклассов вашего дела.

Если вы все еще хотите закодировать его вручную, вы можете использовать синтаксический анализатор readNullable:

val name: Option[Name] = Name(record.as((__ \ "name").readNullable[String]))

Обратите внимание, однако, что с помощью Tryнесколько недоволен в FP и прямое использование JsResult было бы более идиоматичным.

0 голосов
/ 10 ноября 2019

Если вы не заблокированы для использования play-json, позвольте мне показать, как это можно легко сделать с помощью jsoniter-scala :

import com.github.plokhotnyuk.jsoniter_scala.core._
import com.github.plokhotnyuk.jsoniter_scala.macros._

implicit val codec: JsonValueCodec[Seq[Data]] = JsonCodecMaker.make(CodecMakerConfig)

val json: Array[Byte] = """[
  {
    "id": 1248,
    "default": false,
    "name": null,
    "number": 2
  }
]""".getBytes("UTF-8")
val data: Seq[Data] = readFromArray(json)
println(data)

, который выдаст следующий вывод:

List(Data(Some(Id(1248)),None,Some(Number(2))))

Здесь вы можете увидеть пример того, как интегрировать его с платформой Play.

...