标准 Scala 库中的 JSON 支持可能不是最佳选择。不幸的是,Scala 的 JSON 库的情况有点令人困惑,有很多替代方案(Lift JSON、Play JSON、Spray JSON、Twitter JSON、Argonaut ......),基本上一周中的每一天都有一个库......我建议您至少看看这些,看看它们中的任何一个是否更易于使用和更具表现力。
这是一个使用 Play JSON 的示例,我出于特殊原因选择了该示例(能够使用宏生成格式):
object JsonTest extends App {
import play.api.libs.json._
type MyDict = Map[String, Int]
implicit object MyDictFormat extends Format[MyDict] {
def reads(json: JsValue): JsResult[MyDict] = json match {
case JsObject(fields) =>
val b = Map.newBuilder[String, Int]
fields.foreach {
case (k, JsNumber(v)) => b += k -> v.toInt
case other => return JsError(s"Not a (string, number) pair: $other")
}
JsSuccess(b.result())
case _ => JsError(s"Not an object: $json")
}
def writes(m: MyDict): JsValue = {
val fields: Seq[(String, JsValue)] = m.map {
case (k, v) => k -> JsNumber(v)
} (collection.breakOut)
JsObject(fields)
}
}
val m = Map("hallo" -> 12, "gallo" -> 34)
val serial = Json.toJson(m)
val text = Json.stringify(serial)
println(text)
val back = Json.fromJson[MyDict](serial)
assert(back == JsSuccess(m), s"Failed: $back")
}
虽然您可以直接构造和解构JsValues
,但主要思想是使用Format[A]
whereA
是数据结构的类型。这比标准的 Scala-Library JSON 更加强调类型安全。它看起来更冗长,但最终我认为这是更好的方法。
有一些实用方法Json.toJson
,Json.fromJson
它们会寻找您想要的类型的隐式格式。
另一方面,它确实在内存中构建了所有内容,并且确实复制了您的数据结构(因为对于 map 中的每个条目,您将拥有另一个 tuple (String, JsValue)
),因此这不一定是内存效率最高的解决方案,因为您是运行在 GB 量级...
Jerkson 是 Java JSON 库 Jackson 的 Scala 包装器。后者显然具有流式传输数据的功能。我发现这个项目说它增加了流媒体支持。依次播放 JSON 是基于 Jerkson,所以也许您甚至可以弄清楚如何使用它来流式传输您的对象。另请参阅此问题。