web-dev-qa-db-fra.com

Quelle bibliothèque JSON à utiliser dans Scala?

J'ai besoin de construire 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 à la jArray, quelque chose comme jArray += ...

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

112
David Portabella

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

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

  1. parsing.json.JSON - Warning cette bibliothèque n'est disponible que jusqu'à Scala version 2.9.x (supprimée dans les versions plus récentes).
  2. spray-json _ - Extrait du projet Spray
  3. Jerkson ± - Warning une jolie bibliothèque (construite sur Java Jackson) mais maintenant abandonnée. Si vous comptez utiliser cela, suivez probablement l'exemple du projet Scalding et utilisez le fork backchat.io
  4. sjson - de 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 standard AST 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 autonome, voir cette réponse pour plus de détails } _
  9. dijon - Avertissement abandonné. Une bibliothèque Scala JSON à typage dynamique
  10. sonofjson - Bibliothèque JSON visant une API ultra-simple
  11. Jawn - La bibliothèque JSON d'Erik Osheim vise la vitesse de Jackson ou plus rapide
  12. Rapture JSON ± - un frontal JSON pouvant utiliser 2, 4, 5, 6, 7, 11 ou Jackson en tant que back-end
  13. (circe } _ - fork d'Argonaut construit sur chats au lieu de scalaz
  14. jsoniter-scala _ - Macros Scala pour la génération au moment de la compilation de codecs JSON ultra-rapides

§ = intègre Scalaz, ± = prend en charge l'interopérabilité avec Jackson JsonNode

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

192
Alex Dean

Lift-json est à la version 2.6 et cela fonctionne vraiment bien (et est également très bien supporté, le responsable de la maintenance est toujours prêt à corriger les bogues que les utilisateurs trouveront . Vous pouvez en trouver des exemples dans le répertoire github

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

Comme @Alexey le fait remarquer, si vous voulez utiliser la bibliothèque avec une autre version de Scala, dites 2.11.x, changez scalaVersion et 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.

17
fmpwizard

Je suggère d'utiliser jerkson , il prend en charge la plupart des conversions de types 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"}]
15
paradigmatic

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

Vous trouverez ci-dessous un exemple d'utilisation.

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 de JAXB Annotations sont très pratiques. 

Ce billet de blog décrit son utilisation avec JAXB Annotations 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
     }
  }
}   
10
Ramon

Je suis peut-être un peu en retard, mais vous devriez vraiment essayer d'utiliser la bibliothèque JSON à partir de la structure de jeu .. Vous pouvez consulter documentation . Dans la version 2.1.1 actuelle, vous ne pouvez pas l'utiliser séparément sans jouer tout le jeu 2, ainsi 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 un cadre de jeu complet avec toutes les choses à bord. 

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

7
Alex Povar

Voici une implémentation de base d'écriture puis de lecture du fichier json à l'aide de 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)
 }
}
5
Akavall

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

Tout cela sans aucun code inutile, comme des implicites, des lecteurs/graveurs personnalisés pour les cas simples, une API lisible en raison d'une surcharge de l'opérateur ...

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

5
eugen

L'enlèvement semble être absent de la liste des réponses ..__ Il peut être obtenu à partir de http://rapture.io/ et vous permet (entre autre) de:

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

Je ne veux pas copier/coller des exemples de Rapture à partir de cette page. Jon Pretty a présenté les fonctionnalités de Rapture à la SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI

4
Piohen

Jawn est une bibliothèque d’analyseurs JSON très flexible située à Scala. Il permet également de générer des AST personnalisés. il vous suffit de lui fournir un petit trait pour le mapper à l'AST.

Très bien travaillé pour un projet récent nécessitant un peu d’analyse JSON.

4
HRJ

La réponse n ° 7 de @ AlaxDean, Argonaut est le seul que j'ai pu travailler rapidement avec sbt et intellij. En fait, les json4 ont également pris peu de temps, mais traiter avec un AST brut n’est pas ce que je voulais. J'ai obtenu que argonaut travaille en mettant une seule ligne dans mon build.st:

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

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

Et alors 

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

Assurez-vous de bien connaître Option , qui est juste une valeur qui peut aussi ê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), il s'agit probablement de Scalaz. 

3
Bjorn Tipling

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

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

Il y a 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)
}
2
momodi

J'utilise la bibliothèque PLAY JSONvous pouvez trouver le repo mavn pour seulement la bibliothèque JSON, pas tout le cadre 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/

0
Montaro

Laissez-moi aussi vous donner le SON de JSON version:

import nl.typeset.sonofjson._

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

Play a publié son module de traitement de JSON indépendamment de Play Framework, Play WS

A publié un article à ce sujet sur le blog, consultez la page http://pedrorijo.com/blog/scala-json/

En utilisant les classes de cas et Play WS (déjà inclus dans Play Framework), vous convertissez des cas entre json et des classes de cas avec une simple ligne implicite

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
0
pedrorijo91

J'utilise uPickle qui présente le gros avantage de pouvoir 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.sbt pour utiliser uPickle:

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"
0
Matthias Braun