播放Framework和Scala Json,解析包含JSArray和JSObject的json

Posted

技术标签:

【中文标题】播放Framework和Scala Json,解析包含JSArray和JSObject的json【英文标题】:Play Framework and Scala Json, parsing for json containing JSArray and JSObject 【发布时间】:2016-02-16 07:16:34 【问题描述】:

我的示例 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 值或 JS 对象,或者我们可以将其从 JS 值转换为 JS 对象。谢谢。

【问题讨论】:

【参考方案1】:

你可以这样做:

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])

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

【讨论】:

感谢您的回复。是的,我想将单个对象转换为列表。我可以这样写吗?对象 NewUserJson 隐式 val newUserJsonReads: Reads[NewUserJson] = ( (JsPath \ "@version").read[String] and (JsPath \ "country").read[JsValue].map case arr: JsArray => arr. as[Seq[CountryJson]] case obj: JsObject => obj.as[Seq[CountryJson]] )(NewUserJson.apply _) 对于上述情况,我不断收到“应用程序不接受参数错误” 我的回答对你不起作用?当它是单个对象时,您无法将对象读取为 Seq。 它没有用。我也应该更改案例类类型吗? 我更新了答案,案例类应该是:case class NewUserJson(@version: String, country: Seq[CountryJson]) 如果它不适合你,我可以分享完整的例子,以及两个 jsons 通过的测试。告诉我它是否适合你。【参考方案2】:

正在研究 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 _)
    

【讨论】:

Tomer 写了写解决方案。如果你想使用 nullable,你可以将他的代码修改为 "readNullable[JsValue].map_.mapcase arr: JsArray => ...

以上是关于播放Framework和Scala Json,解析包含JSArray和JSObject的json的主要内容,如果未能解决你的问题,请参考以下文章

使用 Scala 播放 Framework 2.4.0 和 I18n

Scala Play Framework 2.6密封特征格式给Json

如何将 IntelliJ 与 Play Framework 和 Scala 一起使用

Scala播放JSON类型转换

Play Framework,Scala - 仅当有新数据可用时才向客户端发送 websocket 消息

scala 使用啥解析json比较好