在Scala中使用哪个JSON库?[关闭]


125

我需要构建一个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 += ...

最接近的图书馆/解决方案是什么?


Answers:


219

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

有很多选择。我没有特别列出它们,并带有注释:

  1. parsing.json.JSON - 警告这个库仅达斯卡拉版本2.9.x(新版本中删除)
  2. spray-json-从Spray项目中提取
  3. Jerkson ±- 警告一个不错的库(建立在Java Jackson之上),但现在已经放弃了。如果要使用此功能,则可以遵循Scalding项目的示例并使用backchat.io分支
  4. sjson-通过Debasish Ghosh
  5. lift-json-可以与Lift项目分开使用
  6. json4s 版本 -从lift-json提取的内容,它试图创建其他JSON库可以使用的标准JSON AST。包括由Jackson支持的实现
  7. 淘金者 💣 § -一个FP-面向JSON库斯卡拉,从后面Scalaz人
  8. play-json ±-现在可以独立使用,有关详细信息,请参见此答案
  9. 第戎 -一个方便,安全和高效的JSON库,在后台使用jsoniter-scala
  10. sonofjson-旨在实现超简单API的JSON库
  11. Jawn -Erik Osheim的JSON库,旨在提高Jackson或更快的速度
  12. Rapture JSON ±-JSON前端,可以使用2、4、5、6、7、11或Jackson作为后端
  13. 瑟茜 💣 -淘金的叉建立在顶部的猫,而不是scalaz
  14. jsoniter-scala -Scala宏,用于在编译时生成超快速J​​SON编解码器
  15. jackson-module-scala - Jackson的附加模块,支持特定于Scala的数据类型
  16. 蛀虫 -高效CBOR和JSON(德)序列化的斯卡拉

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

除雪机,我们使用与杰克逊后端json4s; 我们在Argonaut上也有很好的经验。


8
在较大的LIft项目中捆绑了lift-json是不正确的,您可以仅依赖lift-json,而Lift项目中的其他内容都不会进入您的项目。
fmpwizard 2013年

3
@AlexDean:parsing.json.JSON有什么不好?
Matthias Braun 2013年

看起来play-json将随Play 2.2一起发布,您现在可以使用它了:mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling-好点,现在找不到在2.11中弃用的任何提及。删除了该评论
Alex Dean

2
该列表应将jackson-module-scala放在顶部,这在性能,简单性,维护和支持方面到目前为止是最好的。
lyomi

17

Lift-json的版本为2.6,并且确实运行良好(并且也得到很好的支持,维护人员始终准备修复用户可能发现的任何错误。您可以在github存储库中找到使用它的示例

维护者(Joni Freeman)始终可以在Lift邮件列表中找到。邮件列表上还有其他用户也非常有帮助。

正如@Alexey指出的那样,如果您想将该库与其他Scala版本一起使用,请说2.11.x,如下更改scalaVersion并使用%%

scalaVersion := "2.11.5" 

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

您可以查看liftweb.net网站,以查找最新版本。


3
我也使用lift-json,可以保证它是一个很棒的库。它使解析和生成/序列化JSON非常容易。
丹·西蒙

1
+1代表“ net.liftweb”%“ lift-json_2.10”%“ 2.5.1”
Dylan Hogg

2
对于Scala 2.11:“ net.liftweb”%“ lift-json_2.11”%“ 2.6-M4”
Alexey

15

我建议使用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"}]

2
它还为案例类提供了一些非常出色的支持,这些案例类可以实现一些非常优雅类型安全的JSON处理。
Thomas Lockney 2011年

9
这个图书馆已经被作者遗弃了,还有其他选择吗?
zjffdu 2012年

1
让我们不要忘记rapture.io,它是一个Scala库家族,为常见的编程任务(例如,与I / O,加密以及JSON和XML处理一起使用,提供了美丽的惯用的Scala API)。
Piohen 2014年

12

列表中的第7位是Jackson,未使用Jerkson。它支持Scala对象(案例类等)。

以下是我如何使用它的示例。

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
     }
  }
}   

8

也许我有点迟了,但是您真的应该尝试使用play框架中的json库。您可以查看文档。在当前的2.1.1版本中,如果没有完整版本2,您将无法单独使用它,因此依赖性将如下所示:

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

它将为您带来整个游戏框架,其中包含所有内容。

但是据我所知,Typesafe的人有计划在2.2版本中将其分开。因此,有一个来自2.2快照的独立play-json


2
FYI:Play的JSON库已经在类型安全的快照提供回购:repo.typesafe.com/typesafe/snapshots/com/typesafe/play/...
Tvaroh

...您可以像这样添加。
bluenote10 2014年


5

您应该检查Genson。它比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)

免责声明:我是Gensons的作者,但这不代表我不客观:)


大坝很酷,可惜它只有一个问题github.com/owlike/genson/issues/82
samthebest

5

这是使用写入然后读取json文件的基本实现json4s

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

4

黄麻是Scala中非常灵活的JSON解析器库。它还允许生成自定义AST。您只需要提供一个小的特征即可映射到AST。

对于最近需要一点JSON解析的项目非常有效。


4

答案列表中似乎缺少狂喜。可以从http://rapture.io/获得,并且(除其他事项外)您可以:

  • 选择JSON后端,如果您已经使用过一个(在导入中),这将非常有用
  • 决定是否使用Try,Future,Option,Either等(也用于导入)
  • 只需一行代码即可完成很多工作。

我不想从页面复制/粘贴Rapture示例。Jon Pretty在SBTB 2014上对Rapture的功能做了不错的介绍:https : //www.youtube.com/watch?v= ka5-OLJgybI


3

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

libraryDependencies += "io.argonaut" %% "argonaut" % "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"

确保您熟悉Option,它只是一个也可以为null的值(我猜是null安全的)。Argonaut使用了Scalaz,因此,如果您看到诸如符号\/(或操作)之类的不理解的内容,则可能是Scalaz。


2

您可以尝试以下方法: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)
}

我喜欢这个-非常适合小用例-不需要任何库。
Samik R

2

我使用uPickle,它具有很大的优势,它将自动处理嵌套的case类:

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"

0

我使用PLAY JSON库,您可以在这里找到仅用于JSON库的mavn存储库,而不是整个框架

    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/


上面已经提到了JSON Play。
bluenote10 2014年


0

Play发行了独立于Play框架Play WS的 JSON处理模块

对此发表了博客文章,请访问http://pedrorijo.com/blog/scala-json/

使用案例类和Play WS(已包含在Play Framework中),您可以使用简单的单行隐式在json和案例类之间进行案例转换

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.