Thư viện JSON nào sẽ sử dụng trong Scala? [đóng cửa]


125

Tôi cần xây dựng một chuỗi JSON, đại loại như thế này:

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

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

Tôi cần có thể thêm hàng vào jArray, giống nhưjArray += ...

Thư viện / giải pháp gần nhất cho vấn đề này là gì?


Câu trả lời:


219

Thật không may, viết thư viện JSON là phiên bản mã hóa của ứng dụng cộng đồng Scala.

Có khá nhiều lựa chọn thay thế. Tôi liệt kê chúng không theo thứ tự cụ thể, với ghi chú:

  1. Parsing.json.JSON - Cảnh báo thư viện này chỉ khả dụng cho phiên bản Scala 2.9.x (đã bị xóa trong các phiên bản mới hơn)
  2. Spray-json - Trích xuất từ ​​dự án Spray
  3. Jerkson ± - Cảnh báo một thư viện đẹp (được xây dựng trên đỉnh Java Jackson) nhưng hiện tại đã từ bỏ phần mềm. Nếu bạn định sử dụng cái này, có thể làm theo ví dụ của dự án Scalding và sử dụng ngã ba backchat.io
  4. sjson - Tác giả Debasish Ghosh
  5. thang máy-json - Có thể được sử dụng riêng biệt từ dự án Nâng
  6. json4s 💣 § ± - Một trích xuất từ ​​thang máy-json, đang cố gắng tạo JSON AST tiêu chuẩn mà các thư viện JSON khác có thể sử dụng. Bao gồm một triển khai được Jackson ủng hộ
  7. Argonaut 💣 § - Một thư viện JSON theo định hướng FP cho Scala, từ những người đứng sau Scalaz
  8. play-json ± - Bây giờ có sẵn độc lập, xem câu trả lời này để biết chi tiết
  9. dijon - Một thư viện JSON tiện dụng, an toàn và hiệu quả, sử dụng jsoniter-scala dưới mui xe.
  10. sonofjson - Thư viện JSON nhắm đến một API siêu đơn giản
  11. Jawn - Thư viện JSON của Erik Osheim nhắm đến tốc độ Jackson hoặc nhanh hơn
  12. Rapture JSON ± - một giao diện người dùng JSON có thể sử dụng 2, 4, 5, 6, 7, 11 hoặc Jackson làm back-end
  13. circe 💣 - ngã ​​ba của Argonaut được xây dựng trên đầu mèo thay vì scalaz
  14. jsoniter-scala - Các macro Scala để tạo ra các bộ giải mã JSON cực nhanh
  15. jackson-module-scala - Mô-đun bổ trợ cho Jackson để hỗ trợ các kiểu dữ liệu dành riêng cho Scala
  16. Borer - Tuần tự hóa hiệu quả CBOR và JSON (de) trong Scala

= Chưa sửa các lỗ hổng bảo mật, § = có tích hợp Scalaz, ± = hỗ trợ can thiệp với Jackson JsonNode

Trong Snowplow, chúng tôi sử dụng json4 với back-end Jackson; chúng tôi cũng đã có những trải nghiệm tốt với Argonaut.


8
Không đúng khi thang máy được gói trong dự án LIft lớn hơn, bạn có thể chỉ cần phụ thuộc vào thang máy và không có gì khác từ dự án Thang máy sẽ đến với dự án của bạn.
fmpwizard

3
@AlexDean: Điều gì quá tệ về Parsing.json.JSON?
Matthias Braun

Có vẻ như play-json sẽ được phát hành với Play 2.2 và bạn đã có thể sử dụng ngay bây giờ: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - điểm hay, hiện tại không thể tìm thấy bất kỳ đề cập nào về việc nó bị phản đối trong 2.11. Đã xóa nhận xét đó
Alex Dean

2
Danh sách nên đặt jackson-module-scala lên hàng đầu, từ trước đến nay là tốt nhất cho hiệu suất, đơn giản, bảo trì và hỗ trợ.
lyomi

17

Lift-json là phiên bản 2.6 và nó hoạt động rất tốt (và cũng được hỗ trợ rất tốt, người bảo trì luôn sẵn sàng sửa mọi lỗi mà người dùng có thể tìm thấy. Bạn có thể tìm thấy các ví dụ sử dụng nó trên kho github

Người bảo trì (Joni Freeman) luôn có thể truy cập trong danh sách gửi thư Nâng . Ngoài ra còn có những người dùng khác trong danh sách gửi thư cũng rất hữu ích.

Như @Alexey chỉ ra, nếu bạn muốn sử dụng thư viện với phiên bản Scala khác, hãy nói 2.11.x, thay đổi scalaVersionvà sử dụng %%như sau:

scalaVersion := "2.11.5" 

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

Bạn có thể kiểm tra trang web elevweb.net để tìm ra phiên bản mới nhất khi thời gian trôi qua.


3
Tôi cũng sử dụng thang máy và có thể khẳng định rằng đó là một thư viện tuyệt vời. Nó làm cho cả phân tích cú pháp và tạo / tuần tự hóa JSON rất dễ dàng.
Dan Simon

1
+1 cho "net.liftweb"% "nâng-json_2.10"% "2.5.1"
Dylan Hogg

2
và cho Scala 2.11: "net.liftweb"% "nâng-json_2.11"% "2.6-M4"
Alexey

15

Tôi đề nghị sử dụng jerkson , nó hỗ trợ hầu hết các chuyển đổi loại cơ bản:

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
Nó cũng có một số hỗ trợ thực sự tuyệt vời cho các lớp tình huống có thể giúp xử lý JSON rất thanh lịch an toàn.
Thomas Lockney

9
Thư viện này đã bị tác giả bỏ rơi, liệu có sự thay thế nào không?
zjffdu

1
Chúng ta đừng quên rapture.io , "một nhóm thư viện Scala cung cấp API Scala thành ngữ đẹp cho các tác vụ lập trình phổ biến, như làm việc với I / O, mật mã và xử lý JSON & XML."
Piohen

12

Số 7 trong danh sách là Jackson, không sử dụng Jerkson. Nó có hỗ trợ cho các đối tượng Scala, (các lớp trường hợp, v.v.).

Dưới đây là một ví dụ về cách tôi sử dụng nó.

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

Điều này làm cho nó rất đơn giản. Ngoài ra, XmlSerializer và hỗ trợ cho JAXB Annotations rất tiện dụng.

Bài đăng trên blog này mô tả nó được sử dụng với Chú thích JAXB và Khung phát.

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

Đây là JacksonMapper hiện tại của tôi.

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

Có lẽ tôi đã trễ một chút, nhưng bạn thực sự nên thử sử dụng thư viện json từ khung chơi. Bạn có thể xem tài liệu . Trong bản phát hành 2.1.1 hiện tại, bạn không thể sử dụng riêng nó mà không có toàn bộ phần 2, vì vậy phần phụ thuộc sẽ trông như thế này:

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

Nó sẽ mang lại cho bạn toàn bộ khung chơi với tất cả mọi thứ trên tàu.

Nhưng như tôi biết, những kẻ đến từ Formsafe có kế hoạch tách nó ra trong phiên bản 2.2. Vì vậy, có play-json độc lập từ 2.2 snapshot.


2
FYI: thư viện JSON Play là đã có sẵn trong typesafe snapshot repo: repo.typesafe.com/typesafe/snapshots/com/typesafe/play/...
Tvaroh

... mà bạn có thể thêm như vậy .
bluenote10

Nó được sử dụng chính thức trong hướng dẫn sbt
serv-inc

5

Bạn nên kiểm tra Genson . Nó chỉ hoạt động và dễ sử dụng hơn nhiều so với hầu hết các lựa chọn thay thế hiện có trong Scala. Nó nhanh, có nhiều tính năng và tích hợp với một số lib khác (jodatime, json4s DOM api ...).

Tất cả những thứ đó không có bất kỳ mã không cần thiết ưa thích nào như ẩn ý, ​​trình đọc / ghi tùy chỉnh cho các trường hợp cơ bản, API vô hình do quá tải toán tử ...

Sử dụng nó dễ dàng như:

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)

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của Gensons, nhưng điều đó không có nghĩa là tôi không khách quan :)


Khá tuyệt vời, xấu hổ vì nó có một vấn đề github.com/owlike/genson/issues/82
samthebest

5

Đây là một thực hiện cơ bản của văn bản và sau đó đọc jsontệp bằng cách sử dụng 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

Jawn là một thư viện trình phân tích cú pháp JSON rất linh hoạt trong Scala. Nó cũng cho phép tạo AST tùy chỉnh; bạn chỉ cần cung cấp cho nó một đặc điểm nhỏ để ánh xạ tới AST.

Đã làm việc tuyệt vời cho một dự án gần đây cần một chút phân tích cú pháp JSON.


4

Rapture dường như bị thiếu trong danh sách các câu trả lời. Nó có thể được lấy từ http://rapture.io/ và cho phép bạn (trong số những thứ khác) để:

  • chọn back-end JSON, rất hữu ích nếu bạn đã sử dụng một (trong nhập)
  • quyết định nếu bạn làm việc với Thử, Tương lai, Tùy chọn, Hoặc, v.v. (cũng trong nhập)
  • làm rất nhiều công việc trong một dòng mã.

Tôi không muốn sao chép / dán các ví dụ Rapture từ trang của nó. Một bài thuyết trình hay về các tính năng của Rapture đã được Jon Pretty đưa ra tại SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI


3

Câu trả lời số 7 của @ AlaxDean, Argonaut là người duy nhất tôi có thể làm việc nhanh chóng với sbt và intellij. Trên thực tế json4s cũng mất ít thời gian nhưng xử lý AST thô không phải là điều tôi muốn. Tôi đã làm cho argonaut hoạt động bằng cách đặt một dòng duy nhất vào bản dựng của mình.

libraryDependencies += "io.argonaut" %% "argonaut" % "6.0.1"

Và sau đó là một thử nghiệm đơn giản để xem liệu tôi có thể nhận JSON không:

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

Và sau đó

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

Hãy chắc chắn rằng bạn quen thuộc với Tùy chọn chỉ là một giá trị cũng có thể là null (tôi đoán là không an toàn). Argonaut sử dụng Scalaz vì vậy nếu bạn thấy thứ gì đó bạn không hiểu như biểu tượng \/(một hoặc hoạt động) thì đó có thể là Scalaz.


2

Bạn có thể thử điều này: https://github.com/momodi/Json4Scala

Thật đơn giản và chỉ có một tệp scala với mã dưới 300 dòng.

Có mẫu:

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

Tôi thích điều này - tuyệt vời cho các trường hợp sử dụng nhỏ - không cần bất kỳ thư viện.
Samik R

2

Tôi sử dụng uPickle có lợi thế lớn là nó sẽ tự động xử lý các lớp trường hợp lồng nhau:

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

Thêm phần này vào của bạn build.sbtđể sử dụng uPickle:

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

0

Tôi sử dụng thư viện PLAY JSON, bạn có thể tìm thấy repo mavn chỉ cho thư viện JSON chứ không phải toàn bộ khung ở đây

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

Một hướng dẫn rất tốt về cách sử dụng chúng, có sẵn ở đây:

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 đã được đề cập ở trên.
bluenote10

0

Tôi cũng cung cấp cho bạn phiên bản SON of JSON :

import nl.typeset.sonofjson._

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

Tôi rất thích sử dụng cái này nhưng không thể tìm ra cách thêm nó vào phần phụ thuộc của mình vì nó không có trong maven.
Jason Wolosonovich

0

Play đã phát hành mô-đun để xử lý JSON độc lập với Play Framework, Play WS

Tạo một bài đăng trên blog về điều đó, hãy xem tại http://pedrorijo.com/blog/scala-json/

Sử dụng các lớp tình huống và Play WS (đã được bao gồm trong Play Framework), bạn chuyển đổi trường hợp giữa json và các lớp tình huống với một ẩn đơn giản

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.