由于我正在编写一个函数来从我的Scala代码中的另一个API请求数据,因此响应Json的格式如下:
"data": {
"attributeName": "some String",
"attributeValue": false,
"attributeSource": "Manual",
"attributeValueLabel": null
},
"data": {
"attributeName": "some String",
"attributeValue": "daily",
"attributeSource": "Manual",
"attributeValueLabel": "Almost Daily"
}
请注意,有时attributeValue
的类型为String
值,有时则为Boolean
值。
所以我试图编写自己的Reads and Writes来动态读取类型。
case class Data(attributeName: Option[String], attributeValue: Option[String], attributeSource: Option[String], attributeValueLabel: Option[String])
object Data{
implicit val readsData: Reads[Data] = {
new Reads[Data] {
def reads(json: JsValue) = {
val attrValue = (json \ "attributeValue").as[] // How to cast to Boolean some time, but some other time is a String here
......
}
}
}
正如您在我的评论中所看到的那样,我根据API的返回类型,坚持将(json \ "attributeValue")
强制转换为String/Boolean
。我怎么能这样做?
答案 0 :(得分:1)
您可以先尝试将其解析为String
,然后再解析为Boolean
:
val strO = (json \ "attributeValue").asOpt[String]
val value: Option[String] = strO match {
case str@Some(_) => str
case None => (json \ "attributeValue").asOpt[Boolean].map(_.toString)
}
答案 1 :(得分:1)
当您尝试以不同方式读取属性时,可以使用.orElse
函数:
import play.api.libs.json.{JsPath, Json, Reads}
import play.api.libs.functional.syntax._
val json1 =
"""
|{
| "attributeName": "some String",
| "attributeValue": false
|}
""".stripMargin
val json2 =
"""
|{
| "attributeName": "some String",
| "attributeValue": "daily"
|}
""".stripMargin
// I modified you case class to make the example short
case class Data(attributeName: String, attributeValue: String)
object Data {
// No need to define a reads function, just assign the value
implicit val readsData: Reads[Data] = (
(JsPath \ "attributeName").read[String] and
// Try to read String, then fallback to Boolean (which maps into String)
(JsPath \ "attributeValue").read[String].orElse((JsPath \ "attributeValue").read[Boolean].map(_.toString))
)(Data.apply _)
}
println(Json.parse(json1).as[Data])
println(Json.parse(json2).as[Data])
输出:
Data(some String,false)
Data(some String,daily)