2015-10-18 139 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 _) 
}