Play Framework和Scala Json,解析json包含JSArray和JSObject

时间:2016-02-16 07:16:34

标签: json scala playframework-2.4

我的示例json要么是国家/地区对象 Json样本1

  "@version": "1.0",
    "country": {
        "@country": "US",
        "day": {
            "@date": "2016-02-15",
            "@value": "1"
        }
    }

或使用国家/地区数组: Json样本2

"@version": "1.0",
    "country": [{
        "@country": "US",
        "day": {
            "@date": "2016-02-15",
            "@value": "1"
        }
    }, {
        "@country": "UK",
        "day": {
            "@date": "2016-02-15",
            "@value": "5"
        }]
    }

阅读json

 implicit val dayJsonReads: Reads[DayJson] = (
      (JsPath \ "@date").read[DateTime](dateReads) and
        ((JsPath \ "@value").read[Int] orElse (JsPath \ "@value").read[String].map(_.toInt))
      )(DayJson.apply _)

    implicit val countryJsonReads: Reads[CountryJson] = (
      (JsPath \ "@country").read[String] and
        (JsPath \ "day").read[DayJson]
      )(CountryJson.apply _)

 implicit val newUserJsonReads: Reads[NewUserJson] = (
      (JsPath \ "@version").read[String] and
        (JsPath \ "country").readNullable[Seq[CountryJson]] 
      )(NewUserJsonParent.apply _)

以上代码读取示例json 2但是对于示例json 1失败。是否可以使用readNullable来读取JS Value或JS Object,或者我们可以将它从JS Value转换为JS Object。谢谢。

2 个答案:

答案 0 :(得分:4)

您可以这样做:

object NewUserJson{
implicit val newUserJsonReads: Reads[NewUserJson] = (
  (JsPath \ "@version").read[String] and
    (JsPath \ "country").read[JsValue].map{
      case arr: JsArray => arr.as[Seq[CountryJson]]
      case obj: JsObject => Seq(obj.as[CountryJson])
    }
  )(NewUserJson.apply _)
}

这适用于此案例类:

case class NewUserJson(`@version`: String, country: Seq[CountryJson])

但是我不喜欢它,你不能只使用相同的结构吗?当你只有一个国家只发送一个只包含一个国家的列表而不是对象?

答案 1 :(得分:1)

使用Tomer的解决方案,下面是一个工作样本。如果我能让它更紧凑,那就太好了。

案例类

case class NewUserJson(version: String, country: Option[Seq[CountryJson]])

Json解析对象

 object NewUserJson{
    implicit val newUserJsonReads: Reads[NewUserJson] = (
      (JsPath \ "@version").read[String] and
        (JsPath \ "country").readNullable[JsValue].map {
          arr => {
            if (!arr.isEmpty){
              arr.get match {
                case arr: JsArray => Option(arr.as[Seq[CountryJson]])
                case arr: JsObject => Option(Seq(arr.as[CountryJson]))
              }
            }else {
              None
            }
          }
        }
      )(NewUserJson.apply _)
    }