Quale libreria JSON da utilizzare in Scala? [chiuso]


125

Ho bisogno di costruire una stringa JSON, qualcosa del genere:

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

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

Devo essere in grado di aggiungere righe al jArray, qualcosa del generejArray += ...

Qual è la libreria / soluzione più vicina a questa?


Risposte:


219

Sfortunatamente la scrittura di una libreria JSON è la versione della comunità Scala di codifica di un'app di todo list.

Esistono diverse alternative. Li elenco in nessun ordine particolare, con note:

  1. parsing.json.JSON - Avviso questa libreria è disponibile solo fino alla versione 2.9.x di Scala (rimossa nelle versioni più recenti)
  2. spray-json - Estratto dal progetto Spray
  3. Jerkson ± - Avviso di una bella libreria (costruita sulla parte superiore di Java Jackson) ma ora abbandonare. Se hai intenzione di usarlo, probabilmente segui l'esempio del progetto Scalding e usa il fork backchat.io
  4. sjson - di Debasish Ghosh
  5. lift-json - Può essere utilizzato separatamente dal progetto Lift
  6. json4s 💣 § ± - Un'estrazione da lift-json, che sta tentando di creare un AST JSON standard utilizzabile da altre librerie JSON. Include un'implementazione supportata da Jackson
  7. Argonaut 💣 § - Una libreria JSON orientata all'FP per Scala, dalle persone dietro Scalaz
  8. play-json ± - Ora disponibile autonomo, vedere questa risposta per i dettagli
  9. dijon - Una libreria JSON pratica, sicura ed efficiente, utilizza jsoniter-scala sotto il cofano.
  10. sonofjson : libreria JSON che mira a un'API semplicissima
  11. Jawn - libreria JSON di Erik Osheim che punta alla velocità di Jackson o più veloce
  12. Rapture JSON ± - un front-end JSON che può utilizzare 2, 4, 5, 6, 7, 11 o Jackson come back-end
  13. circe 💣 - forchetta di Argonaut costruita sulla cima di gatti invece di scalaz
  14. jsoniter-scala - Macro Scala per la generazione in tempo di compilazione di codec JSON ultraveloci
  15. jackson-module-scala - Modulo aggiuntivo per Jackson per supportare tipi di dati specifici per Scala
  16. Borer - CBOR efficiente e JSON (de) serializzazione in Scala

💣 = non ha risolto le vulnerabilità di sicurezza, § = ha l'integrazione di Scalaz, ± = supporta l'interoperabilità con Jackson JsonNode

In Spazzaneve usiamo json4s con il back-end Jackson; abbiamo avuto buone esperienze anche con Argonaut.


8
Non è vero che lift-json è integrato nel più grande progetto LIft, puoi semplicemente dipendere da lift-json e nient'altro dal progetto Lift arriverà nel tuo progetto.
fmpwizard,

3
@AlexDean: Cosa c'è di così brutto in parsing.json.JSON?
Matthias Braun,

Sembra che il play-json sarà rilasciato con Play 2.2 e puoi già usarlo ora: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - buon punto, non riesco a trovare alcuna menzione ora che è deprecato in 2.11. Rimosso quel commento
Alex Dean il

2
L'elenco dovrebbe mettere jackson-module-scala in cima, che ha di gran lunga il meglio per prestazioni, semplicità, manutenzione e supporto.
Lyomi,

17

Lift-json è alla versione 2.6 e funziona davvero bene (ed è anche molto ben supportato, il manutentore è sempre pronto a correggere eventuali bug che gli utenti possono trovare. Puoi trovarne degli esempi nel repository github

Il manutentore (Joni Freeman) è sempre raggiungibile nella mailing list di Lift . Ci sono anche altri utenti nella mailing list che sono anche molto utili.

Come sottolinea @Alexey, se si desidera utilizzare la libreria con un'altra versione di Scala, dire 2.11.x, modificare scalaVersione utilizzare %%come segue:

scalaVersion := "2.11.5" 

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

È possibile controllare il sito liftweb.net per scoprire l'ultima versione con il passare del tempo.


3
Uso anche lift-json e posso garantire che è un'ottima libreria. Rende molto semplice sia l'analisi che la generazione / serializzazione di JSON.
Dan Simon,

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

2
e per Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey,

15

Suggerisco di usare jerkson , supporta la maggior parte delle conversioni di tipo base:

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
Ha anche un supporto davvero eccezionale per le classi di casi che possono rendere la gestione JSON molto elegante e sicura.
Thomas Lockney,

9
Questa biblioteca è stata abbandonata dall'autore, c'è qualche alternativa?
zjffdu,

1
Non dimentichiamoci di rapture.io , che "è una famiglia di librerie Scala che fornisce bellissime API Scala idiomatiche per attività di programmazione comuni, come lavorare con I / O, crittografia ed elaborazione JSON e XML".
Piohen,

12

Il numero 7 nell'elenco è Jackson, non usando Jerkson. Ha il supporto per gli oggetti Scala, (case case ecc.).

Di seguito è riportato un esempio di come lo uso.

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

Questo lo rende molto semplice. Inoltre è XmlSerializer e il supporto per le annotazioni JAXB è molto utile.

Questo post sul blog descrive l'utilizzo con Annotazioni JAXB e Play Framework.

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

Ecco il mio attuale 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

Forse sono in ritardo un po ', ma dovresti davvero provare a usare la libreria JSON da Play Framework. Puoi consultare la documentazione . Nell'attuale versione 2.1.1 non è possibile utilizzarlo separatamente senza tutta la riproduzione 2, quindi la dipendenza sarà simile a questa:

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

Ti porterà l'intero framework di gioco con tutte le cose a bordo.

Ma come so ragazzi di Typesafe hanno un piano per separarlo nella versione 2.2. Quindi, c'è play-json standalone da 2.2-snapshot.


2
Cordiali saluti: La libreria JSON di Play è già disponibile nel repository di snapshot Typesafe: repo.typesafe.com/typesafe/snapshots/com/typesafe/play/…
Tvaroh

... che puoi aggiungere in questo modo .
bluenote10

È ufficialmente utilizzato nel tutorial sbt
serv-inc

5

Dovresti controllare Genson . Funziona solo ed è molto più facile da usare rispetto alla maggior parte delle alternative esistenti in Scala. È veloce, ha molte funzionalità e integrazioni con alcune altre librerie (jodatime, json4s DOM api ...).

Tutto ciò senza alcun codice superfluo come impliciti, lettori / scrittori personalizzati per casi di base, API ilisible a causa del sovraccarico dell'operatore ...

Usarlo è facile come:

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)

Disclaimer: sono l'autore di Gensons, ma questo non mi dice che non sono obiettivo :)


Abbastanza bella, peccato che abbia un problema github.com/owlike/genson/issues/82
samthebest

5

Ecco un'implementazione di base della scrittura e della lettura del jsonfile utilizzando 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 è una libreria di parser JSON molto flessibile in Scala. Consente inoltre la generazione di AST personalizzati; devi solo fornire un piccolo tratto da mappare all'AST.

Ha funzionato alla grande per un recente progetto che ha richiesto un po 'di analisi JSON.


4

Rapture sembra mancare nell'elenco delle risposte. Può essere ottenuto da http://rapture.io/ e consente (tra l'altro) di:

  • seleziona il back-end JSON, che è molto utile se ne usi già uno (in importazione)
  • decidi se lavori con Try, Future, Option, entrambi, ecc. (anche in importazione)
  • fare molto lavoro in una singola riga di codice.

Non voglio copiare / incollare esempi Rapture dalla sua pagina. Jon Pretty a SBTB 2014 ha tenuto una bella presentazione delle funzionalità di Rapture: https://www.youtube.com/watch?v=ka5-OLJgybI


3

@ 7 Risposta di AlaxDean, Argonaut è l'unico che sono stato in grado di lavorare rapidamente con sbt e intellij. In realtà anche json4s ha richiesto poco tempo, ma gestire un AST non è quello che volevo. Ho fatto funzionare l'argonaut inserendo una sola riga nel mio build.st:

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

E poi un semplice test per vedere se sono riuscito a ottenere 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"))
}

E poi

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

Assicurati di avere familiarità con Opzione, che è solo un valore che può anche essere nullo (immagino nulla di sicuro). Argonaut usa Scalaz, quindi se vedi qualcosa che non capisci come il simbolo \/(o un'operazione) è probabilmente Scalaz.


2

Puoi provare questo: https://github.com/momodi/Json4Scala

È semplice e ha un solo file scala con meno di 300 righe di codice.

Ci sono campioni:

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

Mi piace questo, eccellente per i piccoli casi d'uso, non c'è bisogno di alcuna libreria.
Samik R,

2

Uso uPickle che ha il grande vantaggio di gestire automaticamente le classi di casi nidificati:

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

Aggiungi questo al tuo build.sbtper usare uPickle:

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

0

Uso la libreria PLAY JSON, qui puoi trovare il repository mavn solo per la libreria JSON, non l'intero framework

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

Un ottimo tutorial su come usarli, è disponibile qui:

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 è già stato menzionato sopra.
bluenote10

0

Lascia che ti dia anche la versione del figlio di JSON :

import nl.typeset.sonofjson._

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

Mi piacerebbe usare questo, ma non riesco a capire come aggiungerlo alle mie dipendenze in quanto non è in maven.
Jason Wolosonovich,

0

Play ha rilasciato il suo modulo per gestire JSON indipendentemente da Play Framework, Play WS

Hai pubblicato un post sul blog a riguardo, dai un'occhiata a http://pedrorijo.com/blog/scala-json/

Utilizzando le classi di casi e Play WS (già incluso in Play Framework), converti i casi tra classi json e case con un semplice implicito di una riga

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.