用 JSON4 解构 JSON 数组最优雅的方法是什么?
What's the most elegant way to deconstruct a JSON array with JSON4s?
我必须将以下 JSON 解构为案例列表 classes:
{
"data": [
[49, true, 14, null, null],
[52, false, null, null, null],
[72, true, 4, 2, 1]
]
}
案例class:
case class Data(i1: Int, b: Bool, i2: Option[Int], i3: Option[Int], i4: Option[Int])
我从理解开始,但没能完成:
for {
JArray(data) <- json \ "data"
JArray(d) <- data
JInt(line) <- d.head // ???
} yield Data()
非常感谢任何帮助。
谢谢,
迈克尔
如果您允许包含 Rapture JSON 库,则可以按如下方式完成,仍然使用 JSON4S 后端。这需要以下导入:
import rapture.json._, jsonBackends.json4s._
如果您已经将 JSON 作为 JValue
,您可以将其转换为 Rapture 的 Json
类型,如下所示:
val json = Json(jValue)
鉴于您的案例 class 定义,您需要为 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]]
你可以为Data
写一个CustomSerializer
。
我引入了一个 JOptionInt
提取器来将 JInt
或 JNull
转换为 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)))
我必须将以下 JSON 解构为案例列表 classes:
{
"data": [
[49, true, 14, null, null],
[52, false, null, null, null],
[72, true, 4, 2, 1]
]
}
案例class:
case class Data(i1: Int, b: Bool, i2: Option[Int], i3: Option[Int], i4: Option[Int])
我从理解开始,但没能完成:
for {
JArray(data) <- json \ "data"
JArray(d) <- data
JInt(line) <- d.head // ???
} yield Data()
非常感谢任何帮助。
谢谢,
迈克尔
如果您允许包含 Rapture JSON 库,则可以按如下方式完成,仍然使用 JSON4S 后端。这需要以下导入:
import rapture.json._, jsonBackends.json4s._
如果您已经将 JSON 作为 JValue
,您可以将其转换为 Rapture 的 Json
类型,如下所示:
val json = Json(jValue)
鉴于您的案例 class 定义,您需要为 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]]
你可以为Data
写一个CustomSerializer
。
我引入了一个 JOptionInt
提取器来将 JInt
或 JNull
转换为 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)))