使用 json Play 处理空值
Handling nulls with json Play
我正在尝试使用 Play 库将某些字段的 json 解析为空值。有一个案例class代表数据:
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)))
}
}
使用特定数据类型进行解析不处理 null 情况,因此此实现 returns:
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 中字段的空值?
如果您没有被锁定使用 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 库为您的情况生成 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 会更惯用。
我正在尝试使用 Play 库将某些字段的 json 解析为空值。有一个案例class代表数据:
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)))
}
}
使用特定数据类型进行解析不处理 null 情况,因此此实现 returns:
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 中字段的空值?
如果您没有被锁定使用 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 库为您的情况生成 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 会更惯用。