【问题标题】:Handling nulls with json Play使用 json Play 处理空值
【发布时间】:2019-11-09 19:12:42
【问题描述】:

我正在尝试使用 Play 库为某些字段解析具有空值的 json。有一个表示数据的案例类:

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 中字段的空值?

【问题讨论】:

  • 您的 JSON 在最后一个键/值对之后是否包含尾随逗号?
  • 不,它没有。这是偶然的

标签: scala playframework play-json


【解决方案1】:

您可以简单地让 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]))

但是请注意,在 FP 中使用 Try 有点不受欢迎,而直接使用 JsResult 会更惯用。

【讨论】:

    【解决方案2】:

    如果您没有被锁定使用 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))))
    

    Here你可以看到一个如何将其与 Play 框架集成的示例。

    【讨论】:

    • 好吧,这对我不起作用,因为我只能使用 play-json。
    猜你喜欢
    • 2018-04-22
    • 1970-01-01
    • 2021-08-20
    • 2014-09-23
    • 2019-03-18
    • 2021-06-26
    • 2012-08-15
    • 1970-01-01
    • 2020-12-29
    相关资源
    最近更新 更多