Scala Play中JsValue字段的动态类型转换

时间:2017-11-12 20:23:33

标签: json scala playframework casting

由于我正在编写一个函数来从我的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。我怎么能这样做?

2 个答案:

答案 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)