2015-10-18 85 views
1

指定类型读取JSON场我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" 
     } 
    ] 
} 

,我想使用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”,然后,根据其价值,在“值”字段中读取。所以如果“fieldDataType”是字符串,那么读取“value”作为字符串,如果“fieldDataType”是一个“整数”,然后读取“值”作为整数等。

回答

2

首先,我确实允许自己改变您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 _) 
}