Pustaka JSON apa yang digunakan di Scala? [Tutup]


125

Saya perlu membuat string JSON, seperti ini:

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

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

Saya harus dapat menambahkan baris ke jArray, sesuatu sepertijArray += ...

Apa perpustakaan / solusi terdekat untuk ini?


Jawaban:


219

Sayangnya menulis perpustakaan JSON adalah versi komunitas Scala yang mengkode aplikasi daftar todo.

Ada cukup banyak alternatif. Saya daftar mereka tanpa urutan tertentu, dengan catatan:

  1. parsing.json.JSON - Peringatan perpustakaan ini hanya tersedia hingga Scala versi 2.9.x (dihapus dalam versi yang lebih baru)
  2. spray-json - Diekstraksi dari proyek Spray
  3. Jerkson ± - Peringatan perpustakaan yang bagus (dibangun di atas Java Jackson) tetapi sekarang ditinggalkan. Jika Anda akan menggunakan ini, mungkin ikuti contoh proyek Scalding dan gunakan garpu backchat.io
  4. sjson - Oleh Debasish Ghosh
  5. lift-json - Dapat digunakan secara terpisah dari proyek Lift
  6. json4s 💣 § ± - Ekstraksi dari lift-json, yang mencoba membuat JST AST standar yang dapat digunakan oleh pustaka JSON lainnya. Termasuk implementasi yang didukung Jackson
  7. Argonaut 💣 § - Perpustakaan JSON yang berorientasi-FP untuk Scala, dari orang-orang di belakang Scalaz
  8. play-json ± - Sekarang tersedia secara mandiri, lihat jawaban ini untuk detailnya
  9. dijon - Pustaka JSON yang praktis, aman dan efisien, menggunakan jsoniter-scala under hood.
  10. sonofjson - perpustakaan JSON yang bertujuan untuk API super sederhana
  11. Jawn - perpustakaan JSON oleh Erik Osheim bertujuan untuk kecepatan Jackson-atau-lebih cepat
  12. Rapture JSON ± - front-end JSON yang dapat menggunakan 2, 4, 5, 6, 7, 11 atau Jackson sebagai ujung-belakang
  13. Circe 💣 - garpu dari Argonaut dibangun di atas kucing bukan scalaz
  14. jsoniter-scala - macro Scala untuk pembuatan waktu codec JSON ultra-cepat
  15. jackson-module-scala - Modul tambahan untuk Jackson untuk mendukung tipe data spesifik-Scala
  16. penggerek - Serialisasi CBOR dan JSON (de) yang efisien di Scala

💣 = belum memperbaiki kerentanan keamanan, § = memiliki integrasi Scalaz, ± = mendukung interop dengan Jackson JsonNode

Dalam Snowplow kita menggunakan json4s dengan back-end Jackson; kami memiliki pengalaman yang baik dengan Argonaut juga.


8
Itu tidak benar bahwa lift-json dibundel dalam proyek LIft yang lebih besar, Anda hanya dapat bergantung pada lift-json dan tidak ada yang lain dari proyek Lift yang akan datang ke proyek Anda.
fmpwizard

3
@AlexDean: Apa yang buruk tentang parsing.json.JSON?
Matthias Braun

Sepertinya play-json akan dirilis dengan Play 2.2 dan Anda sudah dapat menggunakannya sekarang: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - poin yang bagus, tidak dapat menemukan penyebutan yang sekarang sudah tidak berlaku lagi pada 2.11. Menghapus komentar itu
Alex Dean

2
Daftar ini harus menempatkan jackson-module-scala di bagian atas, yang sejauh ini merupakan yang terbaik untuk kinerja, kesederhanaan, pemeliharaan, dan dukungan.
lyomi

17

Lift-json ada di versi 2.6 dan berfungsi dengan sangat baik (dan juga didukung dengan sangat baik, pengelola selalu siap untuk memperbaiki bug yang ditemukan pengguna. Anda dapat menemukan contoh menggunakannya di repositori github

Pemelihara (Joni Freeman) selalu dapat dijangkau di milis Lift . Ada juga pengguna lain di milis yang juga sangat membantu.

Seperti yang ditunjukkan oleh @Alexey, jika Anda ingin menggunakan perpustakaan dengan versi Scala lainnya, katakan 2.11.x, ubah scalaVersiondan gunakan %%sebagai berikut:

scalaVersion := "2.11.5" 

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

Anda dapat memeriksa situs liftweb.net untuk mengetahui versi terbaru seiring berjalannya waktu.


3
Saya menggunakan lift-json juga dan dapat menjamin bahwa itu adalah perpustakaan yang hebat. Itu membuat penguraian dan pembuatan / pembuatan serial JSON sangat mudah.
Dan Simon

1
+1 untuk "net.liftweb"% "lift-json_2.10"% "2.5.1"
Dylan Hogg

2
dan untuk Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey

15

Saya sarankan menggunakan jerkson , ini mendukung sebagian besar konversi tipe dasar:

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
Ini juga memiliki beberapa dukungan yang sangat luar biasa untuk kelas kasus yang dapat membuat penanganan JSON yang sangat elegan dan aman.
Thomas Lockney

9
Perpustakaan ini telah ditinggalkan oleh penulis, apakah ada alternatif lain?
zjffdu

1
Jangan lupa tentang rapture.io , yang "adalah keluarga perpustakaan Scala yang menyediakan API Scala idiomatis yang indah untuk tugas pemrograman umum, seperti bekerja dengan I / O, kriptografi, dan pemrosesan JSON & XML."
Piohen

12

Nomor 7 dalam daftar adalah Jackson, tidak menggunakan Jerkson. Ini memiliki dukungan untuk objek Scala, (kelas kasus dll).

Di bawah ini adalah contoh bagaimana saya menggunakannya.

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

Ini membuatnya sangat sederhana. Selain itu, XmlSerializer dan dukungan untuk JAXB Annotations sangat berguna.

Posting blog ini menjelaskan penggunaannya dengan JAXB Annotations dan Play Framework.

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

Ini adalah JacksonMapper saya saat ini.

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

Mungkin saya sedikit terlambat, tetapi Anda benar-benar harus mencoba menggunakan json library dari play framework. Anda bisa melihat dokumentasi . Dalam rilis 2.1.1 saat ini Anda tidak dapat menggunakannya secara terpisah tanpa seluruh permainan 2, jadi ketergantungannya akan terlihat seperti ini:

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

Ini akan membawa Anda seluruh kerangka bermain dengan semua hal di papan.

Tapi seperti yang saya tahu orang-orang dari Typesafe punya rencana untuk memisahkannya di rilis 2.2. Jadi, ada play-json mandiri dari 2.2-snapshot.


2
FYI: Pustaka JSON Play sudah tersedia di Snapshot typesafe repo: repo.typesafe.com/typesafe/snapshots/com/typesafe/play/…
Tvaroh

... yang dapat Anda tambahkan seperti itu .
bluenote10

Ini secara resmi digunakan dalam tutorial sbt
serv-inc

5

Anda harus memeriksa Genson . Ini hanya berfungsi dan jauh lebih mudah digunakan daripada sebagian besar alternatif yang ada di Scala. Cepat, memiliki banyak fitur dan integrasi dengan beberapa lib lainnya (jodatime, json4s DOM api ...).

Semua itu tanpa kode mewah yang tidak perlu seperti implisit, pembaca / penulis khusus untuk kasus dasar, API yang dapat diterima karena kelebihan operator ...

Menggunakannya semudah:

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)

Penafian: Saya penulis Gensons, tapi itu tidak berarti saya tidak objektif :)


Cukup bendungan keren, malu memiliki satu masalah github.com/owlike/genson/issues/82
samthebest

5

Berikut ini adalah implementasi dasar penulisan dan kemudian membaca jsonfile menggunakan 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 adalah parser JSON library yang sangat fleksibel di Scala. Ini juga memungkinkan pembuatan AST khusus; Anda hanya perlu menyediakannya dengan sifat kecil untuk memetakan ke AST.

Bekerja sangat baik untuk proyek terbaru yang membutuhkan sedikit penguraian JSON.


4

Pengangkatan tampaknya tidak ada dalam daftar jawaban. Itu dapat diperoleh dari http://rapture.io/ dan memungkinkan Anda (antara lain) untuk:

  • pilih JSON back-end, yang sangat berguna jika Anda sudah menggunakan satu (di impor)
  • putuskan apakah Anda bekerja dengan Try, Future, Option, Either, etc. (juga dalam impor)
  • melakukan banyak pekerjaan dalam satu baris kode.

Saya tidak ingin menyalin / menempelkan contoh Rapture dari halaman itu. Presentasi yang bagus tentang fitur-fitur Rapture diberikan oleh Jon Pretty di SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI


3

@ AlaxDean # 7 menjawab, Argonaut adalah satu-satunya yang saya dapat bekerja dengan cepat dengan sbt dan intellij. Sebenarnya json4s juga butuh sedikit waktu tetapi berurusan dengan AST mentah bukan yang saya inginkan. Saya mendapat argonaut untuk bekerja dengan memasukkan satu baris ke build.st saya:

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

Dan kemudian tes sederhana untuk melihat apakah saya bisa mendapatkan 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"))
}

Lalu

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

Pastikan Anda terbiasa dengan Opsi yang hanya merupakan nilai yang juga bisa nol (saya kira nol aman). Argonaut menggunakan Scalaz jadi jika Anda melihat sesuatu yang tidak Anda mengerti seperti simbol \/(atau operasi) itu mungkin Scalaz.


2

Anda dapat mencoba ini: https://github.com/momodi/Json4Scala

Ini sederhana, dan hanya memiliki satu file scala dengan kode kurang dari 300 baris.

Ada sampel:

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

Saya suka ini - sangat baik untuk kasus penggunaan kecil - tidak perlu untuk perpustakaan.
Samik R

2

Saya menggunakan uPickle yang memiliki keuntungan besar karena ia akan menangani kelas kasus bersarang secara otomatis:

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

Tambahkan ini ke Anda build.sbtuntuk menggunakan uPickle:

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

0

Saya menggunakan PLAY JSON library Anda dapat menemukan repo mavn hanya untuk perpustakaan JSON bukan seluruh kerangka kerja di sini

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

Tutorial yang sangat bagus tentang cara menggunakannya, tersedia di sini:

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 sudah disebutkan di atas.
bluenote10

0

Biarkan saya juga memberi Anda versi SON of JSON :

import nl.typeset.sonofjson._

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

Saya ingin menggunakan ini tetapi tidak tahu cara menambahkannya ke dependensi saya karena tidak ada pakar.
Jason Wolosonovich

0

Play merilis modulnya untuk berurusan dengan JSON secara independen dari Play Framework, Play WS

Membuat posting blog tentang itu, lihat di http://pedrorijo.com/blog/scala-json/

Menggunakan kelas kasus, dan Play WS (sudah termasuk dalam Play Framework) Anda mengonversi kasus antara json dan kelas kasus dengan implisit satu garis sederhana

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.