在 Scala 中使用什么 JSON 库?

我需要构建一个 JSON 字符串,如下所示:

[
{ 'id': 1, 'name': 'John'},
{ 'id': 2, 'name': 'Dani'}
]


val jArray = JsArray();
jArray += (("id", "1"), ("name", "John"))
jArray += (("id", "2"), ("name", "Dani"))
println(jArray.dump)

我需要能够添加行到 jArray,类似于 jArray += ...

与此最接近的库/解决方案是什么?

121438 次浏览

我建议使用 Jerkson,它支持最基本的类型转换:

scala> import com.codahale.jerkson.Json._


scala> val l = List(
Map( "id" -> 1, "name" -> "John" ),
Map( "id" -> 2, "name" -> "Dani")
)


scala> generate( l )


res1: String = [{"id":1,"name":"John"},{"id":2,"name":"Dani"}]

Lift-json 的版本是2.6,它工作得非常好(并且支持非常好,维护人员随时准备修复用户可能发现的任何 bug。 您可以在 < a href = “ https://github.com/Lift/Framework/tree/master/core/json”rel = “ nofollow”> github 存储库中找到使用它的示例

维护人员(Joni Freeman)总是可以在 电梯邮寄列表中找到。邮件列表中还有其他非常有用的用户。

正如@Alexey 指出的,如果你想使用其他 Scala 版本的库,比如说 2.11.x,改变 scalaVersion并使用 %%,如下所示:

scalaVersion := "2.11.5"


"net.liftweb" %% "lift-json" % "2.6"

随着时间的推移,你可以在 Liftweb.net网站上找到最新的版本。

不幸的是,编写 JSON 库是 Scala 社区编写 todo 列表应用程序的版本。

可供选择的方法有很多,我没有按照特定的顺序列出来,并附上注释:

  1. JSON -警告这个库只能在 Scala 版本2.9. x 之前使用(在更新的版本中删除了)
  2. Spray-json -从 Spray 项目中提取
  3. Jerkson ±-警告一个很好的库(构建在 Java Jackson 之上) ,但现在已经废弃了。如果你打算使用它,可能会遵循 Scalding 项目的例子,使用 < a href = “ https://github.com/backchatio/jerkson”rel = “ noReferrer”> backchat.io fork
  4. 作者: Debasish Ghosh
  5. Lift-json -可与 Lift 项目分开使用
  6. Json4s < a href = “ https://github.com/json4s/json4s/issues? utf8 =% E2% 9C% 93 & amp ±-一个来自 Lift-JSON 的提取,它试图创建一个其他 JSON 库可以使用的标准 JSON AST。包括 Jackson 支持的实现
  7. 阿格诺特人(Arganot.com) 一个面向 FP 的 Scala JSON 库,来自 Scalaz 背后的人
  8. Play-json ±-现在可以单独使用,详情请参阅此答案
  9. Dijon -一个方便、安全、高效的 JSON 库,在引擎盖下使用 Jsoniter-scala
  10. Sonofjson -旨在实现超级简单 API 的 JSON 库
  11. Jawn -Erik Osheim 的 JSON 库,旨在实现“杰克逊或者更快”的速度
  12. Rapture JSON ±-一个可以使用2、4、5、6、7、11或 Jackson 作为后端的 JSON 前端
  13. 的基础上代替 Scalaz 建造了阿格诺的 -fork
  14. Jsoniter-Scala -用于编译时生成超高速 JSON 编解码器的 Scala 宏
  15. Jackson-module-scala -用于 杰克逊的附加模块,以支持特定于 Scala 的数据类型
  16. Borer -Scala 中高效的 CBOR 和 JSON (de)序列化

= 没有固定的安全漏洞,= 有 Scalaz 集成,± = 支持与 Jackson JsonNode的互操作

扫雪机中,我们使用了 json4s 和 Jackson 后端; 我们也有很好的使用 Argo 的经验。

第7位是 Jackson,没有使用 Jerkson。它支持 Scala 对象(case 类等)。

下面是我如何使用它的一个例子。

object MyJacksonMapper extends JacksonMapper
val jsonString = MyJacksonMapper.serializeJson(myObject)
val myNewObject = MyJacksonMapper.deserializeJson[MyCaseClass](jsonString)

此外,XmlSerializer 和对 JAXB 注释的支持非常方便。

这篇博文描述了它与 JAXB 注释和 Play 框架一起使用的情况。

Http://krasserm.blogspot.co.uk/2012/02/using-jaxb-for-xml-and-json-apis-in.html

这是我现在的 JacksonMapper。

trait JacksonMapper {


def jsonSerializer = {
val m = new ObjectMapper()
m.registerModule(DefaultScalaModule)
m
}


def xmlSerializer = {
val m = new XmlMapper()
m.registerModule(DefaultScalaModule)
m
}


def deserializeJson[T: Manifest](value: String): T = jsonSerializer.readValue(value, typeReference[T])
def serializeJson(value: Any) = jsonSerializer.writerWithDefaultPrettyPrinter().writeValueAsString(value)
def deserializeXml[T: Manifest](value: String): T = xmlSerializer.readValue(value, typeReference[T])
def serializeXml(value: Any) = xmlSerializer.writeValueAsString(value)


private[this] def typeReference[T: Manifest] = new TypeReference[T] {
override def getType = typeFromManifest(manifest[T])
}


private[this] def typeFromManifest(m: Manifest[_]): Type = {
if (m.typeArguments.isEmpty) { m.erasure }
else new ParameterizedType {
def getRawType = m.erasure


def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray


def getOwnerType = null
}
}
}

也许我有点晚了,但是您真的应该尝试使用 play 框架中的 json 库。 你可以看看 文件。在当前的2.1.1版本中,如果没有整个 Play 2,你不能单独使用它,所以依赖关系看起来是这样的:

val typesaferepo  = "TypeSafe Repo" at "http://repo.typesafe.com/typesafe/releases"
val play2 = "play" %% "play" % "2.1.1"

它会给你带来整个游戏框架和所有的东西在船上。

但据我所知,Typesafe 的人计划在2.2版本中分离它。因此,有独立的 Play-Json从2.2-快照。

@ AlaxDean 的 # 7答案,阿格诺是唯一一个我能够快速与 sbt 和 intellij 合作的答案。实际上 json4s 也花费了很少的时间,但是处理一个原始的 AST 并不是我想要的。我通过在 build.st 中加入一条单行线来让 argoot 工作:

程序库依赖项 + = “ io.arg”%%% “ arg”% “6.0.1”

然后进行一个简单的测试,看看能否得到 JSON:

package mytest




import scalaz._, Scalaz._
import argonaut._, Argonaut._


object Mytest extends App {


val requestJson  =
"""
{
"userid": "1"
}
""".stripMargin


val updatedJson: Option[Json] = for {
parsed <- requestJson.parseOption
} yield ("name", jString("testuser")) ->: parsed


val obj = updatedJson.get.obj
printf("Updated user: %s\n", updatedJson.toString())
printf("obj : %s\n", obj.toString())
printf("userid: %s\n", obj.get.toMap("userid"))
}

然后

$ sbt
> run
Updated user: Some({"userid":"1","name":"testuser"})
obj : Some(object[("userid","1"),("name","testuser")])
userid: "1"

确保您熟悉 选择,它只是一个值,也可以是 null (我猜是 null safe)。Argo 使用 斯卡拉兹,所以如果你看到一些你不理解的符号,比如 \/(一个或操作) ,它可能是 Scalaz。

我使用 PLAY JSON 库 在这里,您只能找到 JSON 库的 mavn repo,而不能找到整个框架

    val json = "com.typesafe.play" %% "play-json" % version
val typesafe = "typesafe.com" at "http://repo.typesafe.com/typesafe/releases/"

关于如何使用它们的一个非常好的教程可以在这里找到:

Http://mandubian.com/2012/09/08/unveiling-play-2-dot-1-json-api-part1-jspath-reads-combinators/

Http://mandubian.com/2012/10/01/unveiling-play-2-dot-1-json-api-part2-writes-format-combinators/

Http://mandubian.com/2012/10/29/unveiling-play-2-dot-1-json-api-part3-json-transformers/

Jawn 是 Scala 中一个非常灵活的 JSON 解析器库。它还允许生成自定义 AST; 您只需要为它提供一个小的 trait 来映射到 AST。

对于最近的一个需要一点 JSON 解析的项目来说,工作得非常好。

让我也给你 JSON 之子版本:

import nl.typeset.sonofjson._


arr(
obj(id = 1, name = "John)
obj(id = 2, name = "Dani)
)

答案中似乎没有“狂喜”这个词。 它可以从 http://rapture.io/获得,并允许您(除其他外) :

  • 选择 JSON 后端,如果您已经使用了 JSON (在导入中) ,那么这非常有用
  • 决定你是否与尝试,未来,选择,等等(也在导入)
  • 在一行代码中做很多工作。

我不想从它的页面复制/粘贴 Rapture 的例子。Jon Pretty 在 SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI上做了一个关于 Rapture 特性的精彩演示

你应该检查 詹森。 它只是比 Scala 中大多数现有的替代方案更容易使用。它速度很快,具有许多特性,并且与其他一些库(jodatime,json4s DOM api...)进行了集成。

所有这些都没有任何花哨的不必要的代码,比如隐式代码,基本情况下的自定义读写器,由于运算符重载而导致的不可读 API..。

使用它就像下面这样简单:

import com.owlike.genson.defaultGenson_


val json = toJson(Person(Some("foo"), 99))
val person = fromJson[Person]("""{"name": "foo", "age": 99}""")


case class Person(name: Option[String], age: Int)

免责声明: 我是詹森的作者,但这并不意味着我不客观:)

下面是使用 json4s写入和读取 json文件的基本实现。

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._
import java.io._
import scala.io.Source




object MyObject { def main(args: Array[String]) {


val myMap = Map("a" -> List(3,4), "b" -> List(7,8))


// writing a file
val jsonString = pretty(render(myMap))


val pw = new PrintWriter(new File("my_json.json"))
pw.write(jsonString)
pw.close()


// reading a file
val myString = Source.fromFile("my_json.json").mkString
println(myString)


val myJSON = parse(myString)


println(myJSON)


// Converting from JOjbect to plain object
implicit val formats = DefaultFormats
val myOldMap = myJSON.extract[Map[String, List[Int]]]


println(myOldMap)
}
}

你可以试试这个: Https://github.com/momodi/json4scala

它很简单,只有一个 scala 文件,代码少于300行。

有样品:

test("base") {
assert(Json.parse("123").asInt == 123)
assert(Json.parse("-123").asInt == -123)
assert(Json.parse("111111111111111").asLong == 111111111111111l)
assert(Json.parse("true").asBoolean == true)
assert(Json.parse("false").asBoolean == false)
assert(Json.parse("123.123").asDouble == 123.123)
assert(Json.parse("\"aaa\"").asString == "aaa")
assert(Json.parse("\"aaa\"").write() == "\"aaa\"")


val json = Json.Value(Map("a" -> Array(1,2,3), "b" -> Array(4, 5, 6)))
assert(json("a")(0).asInt == 1)
assert(json("b")(1).asInt == 5)
}
test("parse base") {
val str =
"""
{"int":-123, "long": 111111111111111, "string":"asdf", "bool_true": true, "foo":"foo", "bool_false": false}
"""
val json = Json.parse(str)
assert(json.asMap("int").asInt == -123)
assert(json.asMap("long").asLong == 111111111111111l)
assert(json.asMap("string").asString == "asdf")
assert(json.asMap("bool_true").asBoolean == true)
assert(json.asMap("bool_false").asBoolean == false)
println(json.write())
assert(json.write().length > 0)
}
test("parse obj") {
val str =
"""
{"asdf":[1,2,4,{"bbb":"ttt"},432]}
"""
val json = Json.parse(str)
assert(json.asMap("asdf").asArray(0).asInt == 1)
assert(json.asMap("asdf").asArray(3).asMap("bbb").asString == "ttt")
}
test("parse array") {
val str =
"""
[1,2,3,4,{"a":[1,2,3]}]
"""
val json = Json.parse(str)
assert(json.asArray(0).asInt == 1)
assert(json(4)("a")(2).asInt == 3)
assert(json(4)("a")(2).isInt)
assert(json(4)("a").isArray)
assert(json(4)("a").isMap == false)
}
test("real") {
val str = "{\"styles\":[214776380871671808,214783111085424640,214851869216866304,214829406537908224],\"group\":100,\"name\":\"AO4614【金宏达电子】现货库存 质量保证 欢迎购买@\",\"shopgrade\":8,\"price\":0.59,\"shop_id\":60095469,\"C3\":50018869,\"C2\":50024099,\"C1\":50008090,\"imguri\":\"http://img.geilicdn.com/taobao10000177139_425x360.jpg\",\"cag\":50006523,\"soldout\":0,\"C4\":50006523}"
val json = Json.parse(str)
println(json.write())
assert(json.asMap.size > 0)
}

Play 发布了独立于 Play Framework 播放 WS处理 JSON 的模块

我写了篇博文,你可以去 http://pedrorijo.com/blog/scala-json/看看

使用 case 类和 播放 WS(已经包含在 Play Framework 中) ,您可以通过一个简单的一行程序隐式地在 json 和 case 类之间进行 case 转换

case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)


object User {
implicit val userJsonFormat = Json.format[User]
}

我使用的是 泡菜,它有一个很大的优势,那就是它可以自动处理嵌套案例类:

object SerializingApp extends App {


case class Person(name: String, address: Address)


case class Address(street: String, town: String, zipCode: String)


import upickle.default._


val john = Person("John Doe", Address("Elm Street 1", "Springfield", "ABC123"))


val johnAsJson = write(john)
// Prints {"name":"John Doe","address":{"street":"Elm Street 1","town":"Springfield","zipCode":"ABC123"}}
Console.println(johnAsJson)


// Parse the JSON back into a Scala object
Console.println(read[Person](johnAsJson))
}

把这个添加到你的 build.sbt中使用 uPickle:

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"