¿Qué biblioteca JSON usar en Scala? [cerrado]

125

Necesito construir una cadena JSON, algo como esto:

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

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

Necesito poder agregar filas al jArray, algo así comojArray += ...

¿Cuál es la biblioteca / solución más cercana a esto?

David Portabella
fuente

Respuestas:

219

Desafortunadamente, escribir una biblioteca JSON es la versión de la comunidad Scala de codificar una aplicación de lista de tareas pendientes.

Hay una gran variedad de alternativas. Los enumero en ningún orden en particular, con notas:

  1. parsing.json.JSON : advertencia de que esta biblioteca solo está disponible hasta Scala versión 2.9.x (eliminada en versiones más recientes)
  2. spray-json - Extraído del proyecto Spray
  3. Jerkson ± - Advertencia de una buena biblioteca (construida sobre Java Jackson) pero ahora abandonware. Si va a usar esto, probablemente siga el ejemplo del proyecto Scalding y use la bifurcación backchat.io
  4. sjson - Por Debasish Ghosh
  5. lift-json : se puede usar por separado del proyecto Lift
  6. json4s 💣 § ± - Una extracción de lift-json, que intenta crear un AST JSON estándar que otras bibliotecas JSON pueden usar. Incluye una implementación respaldada por Jackson
  7. Argonaut 💣 § - Una biblioteca JSON orientada a FP para Scala, de las personas detrás de Scalaz
  8. play-json ± - Ahora disponible de forma independiente, vea esta respuesta para más detalles
  9. dijon : una biblioteca JSON práctica, segura y eficiente, utiliza jsoniter-scala debajo del capó.
  10. sonofjson : biblioteca JSON que apunta a una API súper simple
  11. Jawn : biblioteca JSON de Erik Osheim que apunta a una velocidad de Jackson o más rápida
  12. Rapture JSON ±: un front-end JSON que puede usar 2, 4, 5, 6, 7, 11 o Jackson como back-end
  13. circe 💣 - tenedor de argonauta construido sobre gatos en lugar de scalaz
  14. jsoniter-scala : macros Scala para la generación en tiempo de compilación de códecs JSON ultrarrápidos
  15. jackson-module-scala : módulo adicional para Jackson que admite tipos de datos específicos de Scala
  16. barrenador - Eficaz serialización CBOR y JSON (de) en Scala

💣 = no ha corregido las vulnerabilidades de seguridad, § = tiene integración Scalaz, ± = admite interoperabilidad con Jackson JsonNode

En Snowplow usamos json4s con el back-end de Jackson; También hemos tenido buenas experiencias con Argonaut.

Alex Dean
fuente
8
No es cierto que lift-json esté incluido dentro del proyecto LIft más grande, simplemente puede depender de lift-json y nada más del proyecto Lift llegará a su proyecto.
fmpwizard
3
@ AlexDean: ¿Qué tiene de malo parsing.json.JSON?
Matthias Braun
Parece que play-json se lanzará con Play 2.2 y ya puedes usarlo ahora: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan
2
@BjornTipling: buen punto, ahora no puedo encontrar ninguna mención de que haya quedado en desuso en 2.11. Eliminado ese comentario
Alex Dean
2
La lista debe colocar jackson-module-scala en la parte superior, que tiene, con mucho, lo mejor para el rendimiento, la simplicidad, el mantenimiento y el soporte.
lyomi
17

Lift-json está en la versión 2.6 y funciona muy bien (y también es muy compatible, el mantenedor siempre está listo para corregir cualquier error que puedan encontrar los usuarios. Puede encontrar ejemplos usándolo en el repositorio de github

El mantenedor (Joni Freeman) siempre está disponible en la lista de correo de Lift . También hay otros usuarios en la lista de correo que también son muy útiles.

Como señala @Alexey, si desea usar la biblioteca con otra versión de Scala, diga 2.11.x, cambie scalaVersiony use de la %%siguiente manera:

scalaVersion := "2.11.5" 

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

Puede consultar el sitio liftweb.net para conocer la última versión a medida que pasa el tiempo.

fmpwizard
fuente
3
También uso lift-json y puedo garantizar que es una gran biblioteca. Hace que analizar y generar / serializar JSON sea muy fácil.
Dan Simon
1
+1 para "net.liftweb"% "lift-json_2.10"% "2.5.1"
Dylan Hogg
2
y para Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey
15

Sugiero usar jerkson , es compatible con la mayoría de las conversiones de tipos básicas:

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"}]
paradigmático
fuente
2
También tiene un soporte realmente impresionante para las clases de casos que pueden hacer un manejo JSON muy elegante y seguro.
Thomas Lockney, el
9
Esta biblioteca ha sido abandonada por el autor, ¿hay alguna alternativa?
zjffdu
1
No nos olvidemos de rapture.io , que "es una familia de bibliotecas de Scala que proporciona hermosas API de Scala idiomáticas para tareas de programación comunes, como trabajar con E / S, criptografía y procesamiento JSON y XML".
Piohen
12

El número 7 en la lista es Jackson, sin usar Jerkson. Tiene soporte para objetos Scala, (clases de casos, etc.).

A continuación se muestra un ejemplo de cómo lo uso.

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

Esto lo hace muy simple. Además es el XmlSerializer y el soporte para las Anotaciones JAXB es muy útil.

Esta publicación de blog describe su uso con JAXB Annotations y Play Framework.

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

Aquí está mi JacksonMapper actual.

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
     }
  }
}   
Ramon
fuente
8

Tal vez llegué un poco tarde, pero realmente deberías intentar usar la biblioteca json del marco de juego. Podrías mirar la documentación . En la versión 2.1.1 actual, no podría usarlo por separado sin el juego completo 2, por lo que la dependencia se verá así:

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

Te traerá un marco de juego completo con todas las cosas a bordo.

Pero como sé, los chicos de Typesafe tienen un plan para separarlo en la versión 2.2. Entonces, hay play-json independiente de 2.2-snapshot.

Alex Povar
fuente
2
FYI: la biblioteca JSON de Play ya está disponible en el repositorio de instantáneas de Typesafe
Tvaroh
... que puedes agregar así .
bluenote10
Se utiliza oficialmente en el tutorial sbt
serv-inc
5

Deberías consultar a Genson . Simplemente funciona y es mucho más fácil de usar que la mayoría de las alternativas existentes en Scala. Es rápido, tiene muchas características e integraciones con algunas otras librerías (jodatime, json4s DOM api ...).

Todo eso sin ningún código sofisticado e innecesario como implicits, lectores / escritores personalizados para casos básicos, API no visible debido a la sobrecarga del operador ...

Usarlo es tan fácil como:

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)

Descargo de responsabilidad: soy el autor de Gensons, pero eso no significa que no soy objetivo :)

Eugen
fuente
Bastante genial, lástima que tenga un problema github.com/owlike/genson/issues/82
samthebest
5

Aquí hay una implementación básica de escritura y lectura de jsonarchivos usando 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)
 }
}
Akavall
fuente
4

Jawn es una biblioteca de analizadores JSON muy flexible en Scala. También permite la generación de AST personalizados; solo necesita proporcionarle un pequeño rasgo para asignar al AST.

Funcionó muy bien para un proyecto reciente que necesitaba un poco de análisis JSON.

HRJ
fuente
4

El éxtasis parece faltar en la lista de respuestas. Se puede obtener de http://rapture.io/ y le permite (entre otras cosas):

  • seleccione el back-end JSON, que es muy útil si ya usa uno (en importación)
  • decida si trabaja con Try, Future, Option, Either, etc. (también en importación)
  • hacer mucho trabajo en una sola línea de código.

No quiero copiar / pegar ejemplos de Rapture desde su página. Jon Pretty dio una bonita presentación sobre las características de Rapture en SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI

Piohen
fuente
3

Respuesta # 7 de @ AlaxDean, Argonaut es la única que pude trabajar rápidamente con sbt e intellij. En realidad, json4s también tomó poco tiempo, pero tratar con un AST sin procesar no es lo que quería. Puse a argonaut a trabajar poniendo una sola línea en mi build.st:

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

Y luego una prueba simple para ver si podría obtener 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"))
}

Y entonces

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

Asegúrese de estar familiarizado con Option, que es solo un valor que también puede ser nulo (nulo seguro, supongo). Argonaut usa Scalaz, así que si ves algo que no entiendes como el símbolo \/(una operación), probablemente sea Scalaz.

Bjorn
fuente
2

Puedes probar esto: https://github.com/momodi/Json4Scala

Es simple y solo tiene un archivo scala con menos de 300 líneas de código.

Hay muestras:

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)
}
momodi
fuente
Me gusta esto, excelente para casos de uso pequeños, sin necesidad de bibliotecas.
Samik R
2

Uso uPickle, que tiene la gran ventaja de que manejará las clases de casos anidados automáticamente:

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

Agregue esto a su build.sbtpara usar uPickle:

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

Utilizo la biblioteca PLAY JSON, puedes encontrar el repositorio mavn solo para la biblioteca JSON, no para todo el marco aquí

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

Aquí hay disponibles muy buenos tutoriales sobre cómo usarlos:

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/

Montaro
fuente
JSON Play ya se mencionó anteriormente.
bluenote10
0

Déjame darte también la versión HIJO de JSON :

import nl.typeset.sonofjson._

arr(
  obj(id = 1, name = "John)
  obj(id = 2, name = "Dani)
)
Wilfred Springer
fuente
Me encantaría usar esto, pero no puedo entender cómo agregarlo a mis dependencias, ya que no está en Maven.
Jason Wolosonovich
0

Play lanzó su módulo para tratar con JSON independientemente de Play Framework, Play WS

Hice una publicación de blog sobre eso, échale un vistazo en http://pedrorijo.com/blog/scala-json/

Al usar las clases de casos y Play WS (ya incluidos en Play Framework), convierte las mayúsculas y minúsculas entre json y las clases de casos con una simple línea implícita

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

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