Welche JSON-Bibliothek soll in Scala verwendet werden? [geschlossen]


125

Ich muss einen JSON-String erstellen, ungefähr so:

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

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

Ich muss in der Lage sein, Zeilen hinzuzufügen jArray, so etwas wiejArray += ...

Was ist die nächstgelegene Bibliothek / Lösung dafür?


Antworten:


219

Leider ist das Schreiben einer JSON-Bibliothek die Version der Scala-Community zum Codieren einer Aufgabenlisten-App.

Es gibt eine Vielzahl von Alternativen. Ich liste sie in keiner bestimmten Reihenfolge mit Anmerkungen auf:

  1. parsing.json.JSON - Warnung, diese Bibliothek ist nur bis Scala Version 2.9.x verfügbar (in neueren Versionen entfernt).
  2. Spray-Json - Aus dem Spray-Projekt extrahiert
  3. Jerkson ± - Warnung vor einer schönen Bibliothek (die auf Java Jackson basiert ), aber jetzt auf Software. Wenn Sie dies verwenden möchten , folgen Sie wahrscheinlich dem Beispiel des Scalding- Projekts und verwenden Sie die Gabel backchat.io
  4. sjson - Von Debasish Ghosh
  5. lift-json - Kann separat vom Lift-Projekt verwendet werden
  6. json4s 💣 § ± - Eine Extraktion aus lift-json, die versucht, einen Standard-JSON-AST zu erstellen, den andere JSON-Bibliotheken verwenden können. Beinhaltet eine von Jackson unterstützte Implementierung
  7. Argonaut 💣 § - Eine FP-orientierte JSON-Bibliothek für Scala von den Leuten hinter Scalaz
  8. play-json ± - Jetzt als Standalone verfügbar. Weitere Informationen finden Sie in dieser Antwort
  9. dijon - Eine handliche, sichere und effiziente JSON-Bibliothek, die jsoniter-scala unter der Haube verwendet.
  10. sonofjson - JSON-Bibliothek mit dem Ziel einer supereinfachen API
  11. Jawn - JSON-Bibliothek von Erik Osheim mit dem Ziel, eine Geschwindigkeit von Jackson oder schneller zu erreichen
  12. Rapture JSON ± - ein JSON-Frontend, das 2, 4, 5, 6, 7, 11 oder Jackson als Backend verwenden kann
  13. circe 💣 - Gabel des Argonauten, die auf Katzen anstelle von Skalaz gebaut wurde
  14. jsoniter-scala - Scala-Makros zur Erzeugung ultraschneller JSON-Codecs zur Kompilierungszeit
  15. jackson-module-scala - Zusatzmodul für Jackson zur Unterstützung von Scala-spezifischen Datentypen
  16. Bohrer - Effiziente CBOR- und JSON (De) Serialisierung in Scala

💣 = hat keine Sicherheitslücken behoben, § = hat Scalaz-Integration, ± = unterstützt Interop mit Jackson JsonNode

In Snowplow verwenden wir json4s mit dem Jackson-Backend. Wir haben auch gute Erfahrungen mit Argonaut gemacht.


8
Es ist nicht wahr, dass lift-json im größeren LIft-Projekt gebündelt ist. Sie können sich einfach auf lift-json verlassen und nichts anderes aus dem Lift-Projekt wird zu Ihrem Projekt kommen.
fmpwizard

3
@AlexDean: Was ist so schlimm an parsing.json.JSON?
Matthias Braun

Es sieht so aus, als würde der Play-Json mit Play 2.2 veröffentlicht und Sie können ihn bereits jetzt verwenden: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - guter Punkt, kann jetzt keine Erwähnung finden, dass es in 2.11 veraltet ist. Dieser Kommentar wurde entfernt
Alex Dean

2
Die Liste sollte Jackson-Modul-Scala an die Spitze setzen, was bei weitem das Beste für Leistung, Einfachheit, Wartung und Support bietet.
Lyomi

17

Lift-json ist in Version 2.6 und funktioniert sehr gut (und wird auch sehr gut unterstützt. Der Betreuer ist immer bereit, alle Fehler zu beheben, die Benutzer möglicherweise finden. Beispiele, die es verwenden, finden Sie im Github-Repository

Der Betreuer (Joni Freeman) ist auf der Lift-Mailingliste immer erreichbar . Es gibt auch andere Benutzer auf der Mailingliste, die ebenfalls sehr hilfreich sind.

Wie @Alexey hervorhebt 2.11.x, ändern scalaVersionund verwenden Sie die Bibliothek %%wie folgt , wenn Sie die Bibliothek mit einer anderen Scala-Version verwenden möchten :

scalaVersion := "2.11.5" 

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

Auf der Website liftweb.net finden Sie im Laufe der Zeit die neueste Version.


3
Ich benutze auch lift-json und kann dafür bürgen, dass es eine großartige Bibliothek ist. Es macht das Parsen und Generieren / Serialisieren von JSON sehr einfach.
Dan Simon

1
+1 für "net.liftweb"% "lift-json_2.10"% "2.5.1"
Dylan Hogg

2
und für Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey

15

Ich schlage vor, jerkson zu verwenden , es unterstützt die meisten grundlegenden Typkonvertierungen:

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
Es bietet auch eine wirklich großartige Unterstützung für Fallklassen, die für eine sehr elegante und typsichere JSON-Handhabung sorgen können .
Thomas Lockney

9
Diese Bibliothek wurde vom Autor verlassen. Gibt es eine Alternative?
Zjffdu

1
Vergessen wir nicht rapture.io , eine "Familie von Scala-Bibliotheken, die wunderschöne idiomatische Scala-APIs für allgemeine Programmieraufgaben wie die Arbeit mit E / A, Kryptografie und JSON- und XML-Verarbeitung bereitstellen".
Piohen

12

Nummer 7 auf der Liste ist Jackson, der Jerkson nicht benutzt. Es unterstützt Scala-Objekte (Fallklassen usw.).

Unten ist ein Beispiel, wie ich es benutze.

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

Das macht es sehr einfach. Darüber hinaus ist der XmlSerializer und die Unterstützung für JAXB Annotations ist sehr praktisch.

Dieser Blog-Beitrag beschreibt die Verwendung mit JAXB Annotations und dem Play Framework.

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

Hier ist mein aktueller 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

Vielleicht bin ich etwas spät dran, aber Sie sollten wirklich versuchen, die JSON-Bibliothek aus dem Play Framework zu verwenden. Sie können sich die Dokumentation ansehen . In der aktuellen Version 2.1.1 können Sie es ohne das gesamte Play 2 nicht separat verwenden. Die Abhängigkeit sieht also folgendermaßen aus:

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

Es wird Ihnen den gesamten Spielrahmen mit allen Dingen an Bord bringen.

Aber wie ich weiß, haben Leute von Typesafe einen Plan, ihn in Version 2.2 zu trennen. Es gibt also einen eigenständigen Play-JSON aus 2.2-Snapshot.



... die Sie hinzufügen können , wie so .
bluenote10

Es wird offiziell im sbt-Tutorial verwendet
serv-inc

5

Sie sollten Genson überprüfen . Es funktioniert einfach und ist viel einfacher zu bedienen als die meisten der in Scala vorhandenen Alternativen. Es ist schnell, hat viele Funktionen und Integrationen mit einigen anderen Bibliotheken (jodatime, json4s DOM api ...).

All das ohne ausgefallenen unnötigen Code wie Implicits, benutzerdefinierte Reader / Writer für grundlegende Fälle, unleserliche API aufgrund von Operatorüberlastung ...

Die Verwendung ist so einfach wie:

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)

Haftungsausschluss: Ich bin Gensons Autor, aber das bedeutet nicht, dass ich nicht objektiv bin :)


Ziemlich
verdammt

5

Hier ist eine grundlegende Implementierung des Schreibens und anschließenden Lesens von jsonDateien mit 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 ist eine sehr flexible JSON-Parser-Bibliothek in Scala. Es ermöglicht auch die Generierung von benutzerdefinierten ASTs. Sie müssen es nur mit einem kleinen Merkmal versehen, um es dem AST zuzuordnen.

Hat hervorragend für ein aktuelles Projekt funktioniert, das ein wenig JSON-Analyse benötigte.


4

Die Entrückung scheint in der Liste der Antworten zu fehlen. Es kann von http://rapture.io/ bezogen werden und ermöglicht Ihnen (unter anderem):

  • Wählen Sie das JSON-Backend aus. Dies ist sehr nützlich, wenn Sie bereits eines verwenden (beim Importieren).
  • Entscheiden Sie, ob Sie mit Try, Future, Option, Entweder usw. arbeiten (auch beim Importieren).
  • Arbeiten Sie viel in einer einzigen Codezeile.

Ich möchte keine Rapture-Beispiele von der Seite kopieren / einfügen. Eine schöne Präsentation über die Funktionen von Rapture hielt Jon Pretty auf der SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI


3

@ AlaxDeans Antwort Nr. 7, Argonaut ist die einzige, bei der ich schnell mit sbt und Intellij arbeiten konnte. Eigentlich hat json4s auch wenig Zeit in Anspruch genommen, aber der Umgang mit einem rohen AST ist nicht das, was ich wollte. Ich habe Argonaut zum Arbeiten gebracht, indem ich eine einzelne Zeile in meine build.st eingefügt habe:

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

Und dann ein einfacher Test, um zu sehen, ob ich JSON bekommen könnte:

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

Und dann

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

Stellen Sie sicher, dass Sie mit Option vertraut sind. Dies ist nur ein Wert, der auch null sein kann (null sicher, denke ich). Argonaut verwendet Scalaz. Wenn Sie also etwas sehen, das Sie nicht verstehen, wie das Symbol \/(eine oder eine Operation), ist es wahrscheinlich Scalaz.


2

Sie können dies versuchen: https://github.com/momodi/Json4Scala

Es ist einfach und hat nur eine Scala-Datei mit weniger als 300 Zeilen Code.

Es gibt Beispiele:

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

Ich mag das - ausgezeichnet für kleine Anwendungsfälle - keine Notwendigkeit für Bibliotheken.
Samik R

2

Ich verwende uPickle, was den großen Vorteil hat, dass verschachtelte Fallklassen automatisch verarbeitet werden:

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

Fügen Sie dies zu Ihrem hinzu build.sbt, um uPickle zu verwenden:

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

0

Ich verwende die PLAY JSON-Bibliothek. Hier finden Sie das mavn-Repo nur für die JSON-Bibliothek, nicht für das gesamte Framework

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

Eine sehr gute Anleitung zur Verwendung finden Sie hier:

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 wurde bereits oben erwähnt.
bluenote10

0

Lassen Sie mich Ihnen auch die SON of JSON- Version geben:

import nl.typeset.sonofjson._

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

Ich würde dies gerne verwenden, kann aber nicht herausfinden, wie ich es zu meinen Abhängigkeiten hinzufügen kann, da es nicht in Maven ist.
Jason Wolosonovich

0

Play hat sein Modul für den Umgang mit JSON unabhängig von Play Framework, Play WS, veröffentlicht

Habe einen Blog-Beitrag darüber verfasst und ihn unter http://pedrorijo.com/blog/scala-json/ gelesen.

Wenn Sie Fallklassen und Play WS (bereits in Play Framework enthalten) verwenden, konvertieren Sie zwischen json- und Fallklassen mit einem einfachen impliziten Einzeiler

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.