Quelle bibliothèque JSON utiliser dans Scala? [fermé]


125

J'ai besoin de créer une chaîne JSON, quelque chose comme ceci:

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

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

Je dois pouvoir ajouter des lignes au jArray, quelque chose commejArray += ...

Quelle est la bibliothèque / solution la plus proche de cela?


Réponses:


219

Malheureusement, l'écriture d'une bibliothèque JSON est la version de la communauté Scala de codage d'une application de liste de tâches.

Il existe une grande variété d'alternatives. Je les énumère sans ordre particulier, avec des notes:

  1. parsing.json.JSON - Attention cette bibliothèque n'est disponible que jusqu'à la version 2.9.x de Scala (supprimée dans les versions plus récentes)
  2. spray-json - Extrait du projet Spray
  3. Jerkson ± - Attention une jolie librairie (construite sur Java Jackson) mais abandonne désormais le logiciel. Si vous comptez utiliser ceci, suivez probablement l'exemple du projet Scalding et utilisez le fork de backchat.io
  4. sjson - Par Debasish Ghosh
  5. lift-json - Peut être utilisé séparément du projet Lift
  6. json4s 💣 § ± - Une extraction de lift-json, qui tente de créer un JSON AST standard que d'autres bibliothèques JSON peuvent utiliser. Inclut une implémentation soutenue par Jackson
  7. Argonaut 💣 § - Une bibliothèque JSON orientée FP pour Scala, des personnes derrière Scalaz
  8. play-json ± - Maintenant disponible en mode autonome, voir cette réponse pour plus de détails
  9. dijon - Une bibliothèque JSON pratique, sûre et efficace, utilise jsoniter-scala sous le capot.
  10. sonofjson - bibliothèque JSON visant une API ultra-simple
  11. Jawn - Bibliothèque JSON d'Erik Osheim visant une vitesse Jackson ou plus rapide
  12. Rapture JSON ± - un frontal JSON qui peut utiliser 2, 4, 5, 6, 7, 11 ou Jackson comme back-ends
  13. circe 💣 - fourche d'Argonaut construit sur des chats au lieu de scalaz
  14. jsoniter-scala - Macros Scala pour la génération à la compilation de codecs JSON ultra-rapides
  15. jackson-module-scala - Module complémentaire pour Jackson pour prendre en charge les types de données spécifiques à Scala
  16. borer - Sérialisation CBOR et JSON (dé) efficace dans Scala

💣 = n'a pas corrigé les vulnérabilités de sécurité, § = a l'intégration Scalaz, ± = prend en charge l'interopérabilité avec Jackson JsonNode

Dans Snowplow, nous utilisons json4s avec le back-end Jackson; nous avons également eu de bonnes expériences avec Argonaut.


8
Il n'est pas vrai que lift-json soit intégré au plus grand projet LIft, vous pouvez simplement compter sur lift-json et rien d'autre du projet Lift ne viendra à votre projet.
fmpwizard

3
@AlexDean: Qu'y a-t-il de si mauvais à parsing.json.JSON?
Matthias Braun

On dirait que le play-json sera publié avec Play 2.2 et vous pouvez déjà l'utiliser maintenant: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan

2
@BjornTipling - bon point, je ne trouve aucune mention maintenant qu'il est obsolète dans la version 2.11. Suppression de ce commentaire
Alex Dean

2
La liste devrait mettre jackson-module-scala en tête, qui a de loin le meilleur pour les performances, la simplicité, la maintenance et le support.
lyomi

17

Lift-json est à la version 2.6 et il fonctionne très bien (et est également très bien supporté, le responsable est toujours prêt à corriger tous les bogues que les utilisateurs peuvent trouver. Vous pouvez trouver des exemples de son utilisation sur le référentiel github

Le responsable (Joni Freeman) est toujours joignable sur la liste de diffusion Lift . Il y a également d'autres utilisateurs sur la liste de diffusion qui sont également très utiles.

Comme le souligne @Alexey, si vous souhaitez utiliser la bibliothèque avec une autre version de Scala, dites 2.11.x, modifiez scalaVersionet utilisez %%comme suit:

scalaVersion := "2.11.5" 

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

Vous pouvez consulter le site liftweb.net pour connaître la dernière version au fil du temps.


3
J'utilise aussi lift-json et je peux garantir que c'est une excellente bibliothèque. Cela facilite l'analyse et la génération / sérialisation de JSON.
Dan Simon

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

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

15

Je suggère d'utiliser jerkson , il prend en charge la plupart des conversions de type de 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
Il offre également un support vraiment impressionnant pour les classes de cas, ce qui peut permettre une gestion JSON très élégante et sécurisée.
Thomas Lockney

9
Cette bibliothèque a été abandonnée par l'auteur, y a-t-il une alternative?
zjffdu

1
N'oublions pas rapture.io , qui "est une famille de bibliothèques Scala fournissant de belles API Scala idiomatiques pour les tâches de programmation courantes, comme le travail avec les E / S, la cryptographie et le traitement JSON et XML."
Piohen

12

Le numéro 7 sur la liste est Jackson, n'utilisant pas Jerkson. Il prend en charge les objets Scala (classes de cas, etc.).

Voici un exemple de la façon dont je l'utilise.

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

Cela rend les choses très simples. De plus, XmlSerializer et la prise en charge des annotations JAXB sont très pratiques.

Cet article de blog décrit son utilisation avec les annotations JAXB et Play Framework.

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

Voici mon JacksonMapper actuel.

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

Peut-être que j'ai un peu de retard, mais vous devriez vraiment essayer d'utiliser la bibliothèque json à partir du framework play. Vous pouvez consulter la documentation . Dans la version 2.1.1 actuelle, vous ne pouviez pas l'utiliser séparément sans jeu complet 2, donc la dépendance ressemblera à ceci:

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

Il vous apportera tout le cadre de jeu avec tout ce qui est à bord.

Mais comme je le sais, les gars de Typesafe ont un plan pour le séparer dans la version 2.2. Donc, il existe un play-json autonome de 2.2-snapshot.


2
Pour info: la bibliothèque JSON de Play est déjà disponible dans le repo d'instantanés de Typesafe
Tvaroh

... que vous pouvez ajouter comme ça .
bluenote10

Il est officiellement utilisé dans le tutoriel sbt
serv-inc

5

Vous devriez vérifier Genson . Cela fonctionne et est beaucoup plus facile à utiliser que la plupart des alternatives existantes dans Scala. Il est rapide, possède de nombreuses fonctionnalités et intégrations avec d'autres bibliothèques (jodatime, json4s DOM api ...).

Tout cela sans aucun code inutile de fantaisie comme des implicits, des lecteurs / écrivains personnalisés pour les cas de base, une API illisible en raison de la surcharge des opérateurs ...

Son utilisation est aussi simple que:

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: Je suis l'auteur de Gensons, mais cela ne veut pas dire que je ne suis pas objectif :)


Plutôt cool, dommage qu'il y ait un problème github.com/owlike/genson/issues/82
samthebest

5

Voici une implémentation de base de l'écriture puis de la lecture de jsonfichiers en utilisant 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 est une bibliothèque d'analyseurs JSON très flexible dans Scala. Il permet également de générer des AST personnalisés; il vous suffit de lui fournir un petit trait pour correspondre à l'AST.

A très bien fonctionné pour un projet récent qui nécessitait un peu d'analyse JSON.


4

Rapture semble manquer dans la liste des réponses. Il peut être obtenu sur http://rapture.io/ et vous permet (entre autres) de:

  • sélectionnez JSON back-end, ce qui est très utile si vous en utilisez déjà un (en import)
  • décidez si vous travaillez avec Try, Future, Option, Either, etc. (également en import)
  • faire beaucoup de travail en une seule ligne de code.

Je ne veux pas copier / coller des exemples de Rapture à partir de sa page. Une belle présentation des fonctionnalités de Rapture a été donnée par Jon Pretty au SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI


3

@ Réponse n ° 7 d'AlaxDean, Argonaut est le seul que j'ai pu utiliser rapidement avec sbt et intellij. En fait, json4s a également pris peu de temps, mais traiter avec un AST brut n'est pas ce que je voulais. J'ai fait travailler Argonaut en insérant une seule ligne dans mon build.st:

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

Et puis un simple test pour voir si je pourrais obtenir 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"))
}

Puis

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

Assurez-vous que vous êtes familier avec Option qui est juste une valeur qui peut également être nulle (null safe je suppose). Argonaut utilise Scalaz donc si vous voyez quelque chose que vous ne comprenez pas comme le symbole \/(une opération ou), c'est probablement Scalaz.


2

Vous pouvez essayer ceci: https://github.com/momodi/Json4Scala

C'est simple et ne contient qu'un seul fichier scala avec moins de 300 lignes de code.

Il existe des échantillons:

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

J'aime cela - excellent pour les petits cas d'utilisation - pas besoin de bibliothèques.
Samik R

2

J'utilise uPickle qui a le gros avantage de gérer automatiquement les classes de cas imbriquées:

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

Ajoutez ceci à votre build.sbtpour utiliser uPickle:

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

0

J'utilise la bibliothèque PLAY JSON, vous pouvez trouver le repo mavn uniquement pour la bibliothèque JSON et non pour l'ensemble du framework ici

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

Un très bon tutoriel sur la façon de les utiliser, est disponible ici:

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 a déjà été mentionné ci-dessus.
bluenote10

0

Permettez-moi également de vous donner la version SON de JSON :

import nl.typeset.sonofjson._

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

J'adorerais l'utiliser mais je ne peux pas comprendre comment l'ajouter à mes dépendances car ce n'est pas dans maven.
Jason Wolosonovich

0

Play a publié son module pour gérer JSON indépendamment de Play Framework, Play WS

J'ai publié un article de blog à ce sujet, consultez-le sur http://pedrorijo.com/blog/scala-json/

En utilisant des classes de cas et Play WS (déjà inclus dans Play Framework), vous convertissez le cas entre les classes json et case avec un simple one-liner implicite

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.