我有如下 JSON:
{
"properties" : {
"timestamp" : "1970-01-01T01:00:00+01:00",
"attributes" : [
{
"name" : "Weather",
"value" : "Cloudy",
"fieldDataType" : "string"
},
{
"name" : "pH",
"value" : 7.2,
"fieldDataType" : "double"
},
{
"name" : "Quality Indicator",
"value" : 2,
"fieldDataType" : "integer"
}
]
}
我想使用 Play JSON 库来解析它。我已经能够处理“时间戳”,但在解析“值”字段时遇到困难,因为它的类型是由“fieldDataType”确定的。到目前为止我已经:
sealed trait AttributeValue
case class AttributeInt(value: Integer) extends AttributeValue
case class AttributeDouble(value: Double) extends AttributeValue
case class AttributeString(value: String) extends AttributeValue
case class Attribute (name: String, value: AttributeValue)
object Attribute {
implicit val attributeReads: Reads[Attribute] = (
(JsPath \ "name").read[String] and
(JsPath \ "fieldDataType").read[String] // ???
)(Attribute.apply _)
}
我希望能够读取“fieldDataType”,然后根据其值读取“value”字段。因此,如果“fieldDataType”是字符串,则将“值”读取为字符串,如果“fieldDataType”是“整数”,则将“值”读取为整数,等等。
最佳答案
首先,我确实允许自己将您的 AttributeInt
声明更改为:
case class AttributeInt(value: Int) extends AttributeValue
使用默认的Int
解析器
接下来你可以定义这样的Reads
提供者:
val attributeByDatatype: PartialFunction[String, JsPath => Reads[AttributeValue]] = {
case "integer" => _.read[Int].map(AttributeInt)
case "double" => _.read[Double].map(AttributeDouble)
case "string" => _.read[String].map(AttributeString)
}
作为 PartialFunction
不仅允许它处理特定的数据类型,还可以提供有关它知道什么数据类型和不知道什么数据类型的信息,这对于 Reads.collect
方法很有用,而生成的 Reads
可以作为 flatMap
现在您可以按如下方式更改您的attributeReads
:
object Attribute {
implicit val attributeReads: Reads[Attribute] = (
(JsPath \ "name").read[String] and
(JsPath \ "fieldDataType")
.read[String]
.collect(ValidationError("datatype unknown"))(attributeByDatatype)
.flatMap(_(JsPath \ "value"))
)(Attribute.apply _)
}
关于json - 根据其他字段指定的类型读取 JSON 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33204107/