【问题标题】:What's the most elegant way to deconstruct a JSON array with JSON4s?用 JSON4s 解构 JSON 数组的最优雅的方法是什么?
【发布时间】:2015-06-23 17:45:53
【问题描述】:

我必须将以下 JSON 解构为案例类列表:

{
  "data": [
    [49, true, 14, null, null],
    [52, false, null, null, null],
    [72, true, 4, 2, 1]
  ]
}

案例类:

case class Data(i1: Int, b: Bool, i2: Option[Int], i3: Option[Int], i4: Option[Int])

我从 for 理解开始,但无法完成:

for {
  JArray(data) <- json \ "data"
  JArray(d) <- data
  JInt(line) <- d.head // ???
} yield Data()

非常感谢任何帮助。

谢谢,

迈克尔

【问题讨论】:

    标签: json scala json4s


    【解决方案1】:

    如果您允许包含 Rapture JSON 库,则可以按如下方式完成,但仍使用 JSON4S 后端。这需要以下导入:

    import rapture.json._, jsonBackends.json4s._
    

    如果您已经将 JSON 作为 JValue,您可以将其转换为 Rapture 的 Json 类型,如下所示:

    val json = Json(jValue)
    

    根据您的案例类定义,您需要为 Data 类型重新定义 JSON 提取器(已经有一个需要 JSON 对象的默认提取器),如下所示:

    implicit val dataExtractor = Json.extractor[Json].map { j =>
      Data(j(0).as[Int], j(1).as[Boolean], j(2).as[Option[Int]],
          j(3).as[Option[Int]], j(4).as[Option[Int]])
    }
    

    然后您可以使用以下命令提取它:

    val list = json.as[List[Data]]
    

    【讨论】:

    • 谢谢,但我宁愿只为此使用 json4s。
    【解决方案2】:

    您可以为Data 写一个CustomSerializer

    我引入了JOptionInt提取器将JIntJNull转换为Option[Int],可以直接在json4s中完成。

    import org.json4s._
    import org.json4s.jackson.JsonMethods._
    import org.json4s.JsonDSL._
    
    case class Data(i1: Int, b: Boolean, i2: Option[Int], i3: Option[Int], i4: Option[Int])
    
    object DataSerializer extends CustomSerializer[Data]( format => ( 
      {
        case JArray(List(JInt(i1), JBool(b), JOptionInt(i2), JOptionInt(i3), JOptionInt(i4))) =>
          Data(i1.toInt, b, i2, i3 , i4) 
      }, {
        case d: Data => JArray(List(d.i1, d.b, d.i2, d.i3, d.i4)) 
      }  
    ))
    
    object JOptionInt {
      def unapply(x: JValue) : Option[Option[Int]] = x match {
        case JInt(i) => Option(Option(i.toInt))
        case JNull   => Option(None)
        case _       => None
      }
    }
    

    可以用作:

    implicit val formats = DataSerializer
    
    val json = parse("""
          {
            "data": [
              [49, true, 14, null, null],
              [52, false, null, null, null],
              [72, true, 4, 2, 1]
            ]
          }
          """)
    
    val result = (json \ "data").extract[Array[Data]]
    // Array(Data(49,true,Some(14),None,None), Data(52,false,None,None,None), Data(72,true,Some(4),Some(2),Some(1)))
    

    【讨论】:

    • 谢谢,完成了!
    猜你喜欢
    • 1970-01-01
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2012-07-09
    • 2018-03-14
    • 1970-01-01
    相关资源
    最近更新 更多