Qual biblioteca JSON usar no Scala? [fechadas]

125

Eu preciso criar uma string JSON, algo como isto:

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

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

Eu preciso poder adicionar linhas ao jArray, algo comojArray += ...

Qual é a biblioteca / solução mais próxima disso?

David Portabella
fonte

Respostas:

219

Infelizmente, escrever uma biblioteca JSON é a versão da comunidade Scala de codificar um aplicativo de lista de tarefas.

Há uma variedade de alternativas. Listo-os em nenhuma ordem específica, com notas:

  1. parsing.json.JSON - Aviso: esta biblioteca está disponível apenas até Scala versão 2.9.x (removida nas versões mais recentes)
  2. spray-json - Extraído do projeto Spray
  3. Jerkson ± - Advertindo uma boa biblioteca (construída sobre Java Jackson), mas agora abandonware. Se você for usar isso, provavelmente siga o exemplo do projeto Scalding e use o fork do backchat.io
  4. sjson - por Debasish Ghosh
  5. lift-json - pode ser usado separadamente do projeto Lift
  6. json4s 💣 § ± - Uma extração de lift-json, que está a tentar criar um padrão JSON AST que outras bibliotecas JSON pode usar. Inclui uma implementação apoiada por Jackson
  7. Argonaut 💣 § - Uma biblioteca JSON orientada para FP para Scala, das pessoas por trás de Scalaz
  8. play-json ± - Agora disponível autônomo, consulte esta resposta para obter detalhes
  9. dijon - Uma biblioteca JSON útil, segura e eficiente, usa o jsoniter-scala sob o capô.
  10. sonofjson - biblioteca JSON visando uma API super simples
  11. Jawn - biblioteca JSON de Erik Osheim, visando velocidade Jackson-ou-mais rápida
  12. Rapture JSON ± - um front-end JSON que pode usar 2, 4, 5, 6, 7, 11 ou Jackson como back-ends
  13. circe 💣 - garfo de argonauta construído em cima de gatos em vez de escalaz
  14. jsoniter-scala - Macros Scala para geração em tempo de compilação de codecs JSON ultrarrápidos
  15. jackson-module-scala - Módulo adicional para Jackson para suportar tipos de dados específicos do Scala
  16. broca - CBOR e JSON (des) serialização eficiente em Scala

💣 = não corrigiu vulnerabilidades de segurança, § = possui integração com Scalaz, ± = suporta interoperabilidade com Jackson JsonNode

No Snowplow , usamos json4s com o back-end de Jackson; também tivemos boas experiências com o Argonaut.

Alex Dean
fonte
8
Não é verdade que o lift-json esteja incluído no projeto LIft maior, você pode simplesmente depender do lift-json e nada mais do projeto Lift chegará ao seu projeto.
Fmpwizard 29/03/2013
3
@AlexDean: O que há de tão ruim em parsing.json.JSON?
Matthias Braun
Parece que o play-json será lançado com o Play 2.2 e você já pode usá-lo agora: mandubian.com/2013/02/21/play-json-stand-alone #
Christiaan
2
@BjornTipling - bom ponto, não consigo encontrar nenhuma menção agora a ser preterida na versão 2.11. Removido esse comentário
Alex Dean
2
A lista deve colocar jackson-module-scala no topo, o que tem de longe o melhor para desempenho, simplicidade, manutenção e suporte.
lyomi 21/07
17

O lift-json está na versão 2.6 e funciona muito bem (e também é muito bem suportado, o mantenedor está sempre pronto para corrigir qualquer erro que o usuário possa encontrar. Você pode encontrar exemplos usando-o no repositório do github

O mantenedor (Joni Freeman) está sempre acessível na lista de correspondência do Lift . Também existem outros usuários na lista de discussão que também são muito úteis.

Como o @Alexey aponta, se você quiser usar a biblioteca com outra versão do Scala, diga 2.11.x, altere scalaVersione use da %%seguinte maneira:

scalaVersion := "2.11.5" 

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

Você pode verificar o site liftweb.net para descobrir a versão mais recente com o passar do tempo.

fmpwizard
fonte
3
Eu uso o lift-json também e posso garantir que é uma ótima biblioteca. Isso facilita a análise e a geração / serialização de JSON.
Dan Simon
1
+1 para "net.liftweb"% "lift-json_2.10"% "2.5.1"
Dylan Hogg
2
e para Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Alexey
15

Sugiro usar jerkson , ele suporta as conversões de tipo mais 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
fonte
2
Ele também possui um suporte realmente impressionante para as classes de casos, o que pode resultar em uma manipulação JSON muito elegante e com segurança de tipo.
Thomas Lockney
9
Esta biblioteca foi abandonada pelo autor, existe alguma alternativa?
zjffdu
1
Não vamos esquecer o rapture.io , que "é uma família de bibliotecas Scala que fornecem belas APIs Scala idiomáticas para tarefas comuns de programação, como trabalhar com E / S, criptografia e processamento JSON e XML".
Piohen
12

O número 7 da lista é Jackson, não usando Jerkson. Tem suporte para objetos Scala (classes de casos, etc.).

Abaixo está um exemplo de como eu o uso.

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

Isso torna muito simples. Além disso, é o XmlSerializer e o suporte para anotações JAXB é muito útil.

Esta postagem do blog descreve seu uso com as Anotações JAXB e o Play Framework.

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

Aqui está o meu JacksonMapper atual.

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
fonte
8

Talvez eu tenha me atrasado um pouco, mas você realmente deve tentar usar a biblioteca json no play framework. Você pode olhar para a documentação . Na versão 2.1.1 atual, você não podia usá-lo separadamente sem o jogo inteiro 2, portanto a dependência será parecida com esta:

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

Ele trará a você toda a estrutura de jogo com todas as coisas a bordo.

Mas como eu sei, os caras da Typesafe têm um plano para separá-lo na versão 2.2. Portanto, existe o play-json independente do 2.2-snapshot.

Alex Povar
fonte
2
FYI: A biblioteca JSON do Play já está disponível no repositório de snapshots Typesafe
Tvaroh
... que você pode adicionar assim .
bluenote10
É oficialmente usado no tutorial sbt
serv-inc
5

Você deve verificar Genson . Apenas funciona e é muito mais fácil de usar do que a maioria das alternativas existentes no Scala. É rápido, possui muitos recursos e integrações com outras bibliotecas (jodatime, json4s DOM api ...).

Tudo isso sem nenhum código desnecessário sofisticado, como implícitos, leitores / gravadores personalizados para casos básicos, API ilisível devido à sobrecarga do operador ...

Usá-lo é tão fácil quanto:

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: Eu sou o autor de Gensons, mas isso não significa que eu não sou objetivo :)

eugen
fonte
Muito legal, pena que tenha um problema github.com/owlike/genson/issues/82 #
samthebest
5

Aqui está uma implementação básica de gravação e leitura de jsonarquivos 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
fonte
4

Jawn é uma biblioteca analisadora JSON muito flexível no Scala. Também permite a geração de ASTs personalizados; você só precisa fornecer uma pequena característica para mapear para o AST.

Funcionou muito bem em um projeto recente que precisava de um pouco de análise JSON.

HRJ
fonte
4

O arrebatamento parece estar ausente na lista de respostas. Pode ser obtido em http://rapture.io/ e permite que você (entre outras coisas):

  • selecione back-end JSON, o que é muito útil se você já usa um (na importação)
  • decida se você trabalha com Try, Future, Option, Either, etc. (também na importação)
  • trabalhe bastante em uma única linha de código.

Não quero copiar / colar exemplos do Rapture da página. Uma bela apresentação sobre os recursos do Rapture foi feita por Jon Pretty no SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI

Piohen
fonte
3

Resposta nº 7 da @ AlaxDean, Argonaut é o único que eu pude trabalhar rapidamente com sbt e intellij. Na verdade, o json4s também levou pouco tempo, mas lidar com um AST bruto não era o que eu queria. Eu consegui o argonaut trabalhar colocando uma única linha no meu build.st:

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

E então um teste simples para ver se eu poderia obter 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 depois

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

Verifique se você está familiarizado com a opção, que é apenas um valor que também pode ser nulo (acho que é seguro como nulo). O Argonaut faz uso do Scalaz, portanto, se você vê algo que não entende como o símbolo \/(uma operação), é provavelmente o Scalaz.

Bjorn
fonte
2

Você pode tentar isso: https://github.com/momodi/Json4Scala

É simples e possui apenas um arquivo scala com menos de 300 linhas de código.

Existem amostras:

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
fonte
Eu gosto disso - excelente para pequenos casos de uso - sem necessidade de bibliotecas.
Samik R
2

Eu uso o uPickle, que tem a grande vantagem de lidar com classes de casos aninhadas automaticamente:

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

Adicione isso ao seu build.sbtpara usar o uPickle:

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

Eu uso a biblioteca PLAY JSON, você pode encontrar o repositório mavn apenas para a biblioteca JSON, não para todo o quadro aqui

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

Tutoriais muito bons sobre como usá-los estão disponíveis aqui:

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
fonte
O JSON Play já foi mencionado acima.
bluenote10
0

Deixe-me também dar a versão SON of JSON :

import nl.typeset.sonofjson._

arr(
  obj(id = 1, name = "John)
  obj(id = 2, name = "Dani)
)
Wilfred Springer
fonte
Eu adoraria usar isso, mas não consigo descobrir como adicioná-lo às minhas dependências, pois não está no maven.
Jason Wolosonovich
0

O Play lançou seu módulo para lidar com o JSON independentemente do Play Framework, Play WS

Fiz um post sobre isso, confira em http://pedrorijo.com/blog/scala-json/

Usando classes de caso e Play WS (já incluído no Play Framework), você converte caso entre json e case com um implemento simples de uma linha

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

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