Какую библиотеку JSON использовать в Scala? [закрыто]

125

Мне нужно создать строку JSON, примерно так:

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

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

Мне нужно добавить строки jArray, например,jArray += ...

Какая библиотека / решение ближе всего к этому?

Дэвид Портабелла
источник

Ответы:

219

К сожалению, написание библиотеки JSON - это версия сообщества Scala для написания приложения со списком задач.

Есть множество альтернатив. Я перечисляю их в произвольном порядке с примечаниями:

  1. parsing.json.JSON - Предупреждение, эта библиотека доступна только до версии Scala 2.9.x (удалена в более новых версиях)
  2. spray-json - извлечен из проекта Spray
  3. Jerkson ± - Предупреждение, хорошая библиотека (построенная поверх Java Jackson), но теперь откажитесь от программного обеспечения. Если вы собираетесь использовать это, возможно, следуйте примеру проекта Scalding и используйте вилку backchat.io
  4. sjson - Автор Дебасиш Гош
  5. lift-json - можно использовать отдельно от проекта Lift
  6. json4s 💣 § ± - Извлечение из lift-json, который пытается создать стандартный JSON AST, который могут использовать другие библиотеки JSON. Включает реализацию, поддерживаемую Джексоном
  7. Argonaut 💣 § - Библиотека JSON для Scala, ориентированная на FP, от разработчиков Scalaz
  8. play-json ± - теперь доступен автономно, подробности см. в этом ответе
  9. dijon - удобная, безопасная и эффективная библиотека JSON, использующая jsoniter-scala под капотом.
  10. sonofjson - библиотека JSON, нацеленная на супер-простой API
  11. Jawn - библиотека JSON от Эрика Осхайма, нацеленная на скорость Джексона или выше
  12. Rapture JSON ± - интерфейс JSON, который может использовать 2, 4, 5, 6, 7, 11 или Джексона в качестве серверных частей.
  13. Цирцея 💣 - вилка Аргонавт построен на вершине кошек вместо scalaz
  14. jsoniter-scala - макросы Scala для генерации сверхбыстрых кодеков JSON во время компиляции
  15. jackson-module-scala - Дополнительный модуль для Jackson для поддержки специфичных для Scala типов данных
  16. borer - Эффективная сериализация CBOR и JSON (де) в Scala

💣 = не исправлены уязвимости безопасности, § = имеет интеграцию со Scalaz, ± = поддерживает взаимодействие с Jackson JsonNode

В снегоочиститель мы используем json4s с Джексоном фоновым; у нас тоже был хороший опыт работы с Аргонавтом.

Алекс Дин
источник
8
Неверно, что lift-json входит в состав более крупного проекта LIft, вы можете просто положиться на lift-json, и больше ничего из проекта Lift в ваш проект не придет.
fmpwizard
3
@AlexDean: Что плохого в parsing.json.JSON?
Маттиас Браун
Похоже, play-json будет выпущен с Play 2.2, и вы уже можете его использовать: mandubian.com/2013/02/21/play-json-stand-alone
Christiaan
2
@BjornTipling - хороший момент, сейчас не могу найти упоминания о том, что он устарел в 2.11. Удален этот комментарий
Alex Dean
2
Список должен поставить на первое место jackson-module-scala , который на сегодняшний день является лучшим по производительности, простоте, обслуживанию и поддержке.
лёми
17

Lift-json имеет версию 2.6, и он работает очень хорошо (и также очень хорошо поддерживается, сопровождающий всегда готов исправить любые ошибки, которые могут найти пользователи. Вы можете найти примеры его использования в репозитории github.

Сопровождающий (Джони Фриман) всегда доступен в списке рассылки Lift . В списке рассылки есть и другие пользователи, которые тоже могут нам помочь.

Как указывает @Alexey, если вы хотите использовать библиотеку с другой версией Scala, скажем 2.11.x, измените scalaVersionи используйте %%следующим образом:

scalaVersion := "2.11.5" 

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

Вы можете проверить сайт liftweb.net, чтобы узнать последнюю версию со временем.

fmpwizard
источник
3
Я также использую lift-json и могу поручиться, что это отличная библиотека. Это упрощает как синтаксический анализ, так и создание / сериализацию JSON.
Дэн Саймон
1
+1 для "net.liftweb"% "lift-json_2.10"% "2.5.1"
Дилан Хогг
2
и для Scala 2.11: "net.liftweb"% "lift-json_2.11"% "2.6-M4"
Алексей
15

Я предлагаю использовать jerkson , он поддерживает большинство основных преобразований типов:

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
Он также имеет отличную поддержку для классов case, которая может обеспечить очень элегантную и безопасную для типов обработку JSON.
Томас Локни
9
Автор отказался от этой библиотеки, есть ли альтернатива?
zjffdu
1
Давайте не будем забывать о rapture.io , который «представляет собой семейство библиотек Scala, предоставляющих красивые идиоматические API-интерфейсы Scala для общих задач программирования, таких как работа с вводом- выводом, криптография и обработка JSON и XML».
Piohen
12

Номер 7 в списке - Джексон, а не Джексон. Он поддерживает объекты Scala (классы case и т. Д.).

Ниже приведен пример того, как я его использую.

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

Это очень просто. Кроме того, есть XmlSerializer и поддержка аннотаций JAXB очень удобна.

В этом сообщении блога описывается его использование с JAXB Annotations и Play Framework.

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

Вот мой текущий 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

Возможно, я немного опоздал, но вам действительно стоит попробовать использовать json-библиотеку из игрового фреймворка. Вы можете посмотреть документацию . В текущем выпуске 2.1.1 вы не могли использовать его отдельно без всей игры 2, поэтому зависимость будет выглядеть так:

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

Это принесет вам всю игровую структуру со всем, что есть на борту.

Но насколько я знаю, ребята из Typesafe планируют отделить его в версии 2.2. Итак, есть отдельный play-json из 2.2-снапшота.

Алекс Повар
источник
2
К вашему сведению: библиотека Play JSON уже доступна в репозитории снимков Typesafe
Tvaroh
... которые вы можете добавить вот так .
bluenote10
Он официально используется в учебнике sbt
serv-inc
5

Вы должны проверить Генсона . Он просто работает и его намного проще использовать, чем большинство существующих альтернатив в Scala. Это быстро, имеет множество функций и интеграции с некоторыми другими библиотеками (jodatime, json4s DOM api ...).

И все это без какого-либо причудливого ненужного кода, такого как имплициты, настраиваемые читатели / писатели для основных случаев, ilisible API из-за перегрузки оператора ...

Использовать его так же просто, как:

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)

Отказ от ответственности: я автор Gensons, но это не значит, что я не объективен :)

Eugen
источник
Довольно круто, жаль, что у него есть одна проблема github.com/owlike/genson/issues/82
samthebest
5

Вот базовая реализация записи, а затем чтения jsonфайла с использованием 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
источник
4

Jawn - очень гибкая библиотека парсера JSON в Scala. Он также позволяет создавать собственные AST; вам просто нужно снабдить его небольшим признаком для сопоставления с AST.

Отлично работал для недавнего проекта, который нуждался в небольшом разборе JSON.

HRJ
источник
4

Кажется, что в списке ответов нет Восторга. Его можно получить на http://rapture.io/ и позволяет (помимо прочего):

  • выберите серверную часть JSON, что очень полезно, если вы уже используете его (при импорте)
  • решить, работаете ли вы с Try, Future, Option, Either и т. д. (также при импорте)
  • выполнять много работы в одной строчке кода.

Я не хочу копировать / вставлять примеры Rapture со страницы. Прекрасная презентация возможностей Rapture была сделана Джоном Претти на SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI

Piohen
источник
3

Ответ @AlaxDean №7, Argonaut - единственный, кого я смог быстро заставить работать с sbt и intellij. На самом деле json4s тоже занимал мало времени, но я не хотел иметь дело с необработанным AST. Я заставил argonaut работать, вставив одну строку в свой build.st:

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

А затем простой тест, чтобы узнать, могу ли я получить 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"))
}

А потом

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

Убедитесь, что вы знакомы с Option, который представляет собой просто значение, которое также может быть нулевым (я полагаю, нулевым). Argonaut использует Scalaz, поэтому, если вы видите что-то, чего не понимаете, например символ \/(или операцию), это, вероятно, Scalaz.

Bjorn
источник
2

Вы можете попробовать это: https://github.com/momodi/Json4Scala

Это просто и содержит только один файл scala с кодом менее 300 строк.

Есть образцы:

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
источник
Мне это нравится - отлично подходит для небольших случаев использования - никаких библиотек не требуется.
Samik R
2

Я использую uPickle, который имеет большое преимущество в том, что он автоматически обрабатывает вложенные классы case:

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

Добавьте это в свой, build.sbtчтобы использовать uPickle:

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"
Маттиас Браун
источник
0

Я использую библиотеку PLAY JSON, здесь вы можете найти репозиторий mavn только для библиотеки JSON, а не для всей структуры

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

Здесь можно найти очень хорошие уроки о том, как их использовать:

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
источник
JSON Play уже упоминался выше.
bluenote10
0

Позвольте мне также дать вам версию SON JSON :

import nl.typeset.sonofjson._

arr(
  obj(id = 1, name = "John)
  obj(id = 2, name = "Dani)
)
Уилфред Спрингер
источник
Я хотел бы использовать это, но не могу понять, как добавить его в свои зависимости, так как его нет в maven.
Джейсон Волосонович
0

Play выпустила свой модуль для работы с JSON независимо от Play Framework, Play WS.

Сделал сообщение об этом в блоге, проверьте его на http://pedrorijo.com/blog/scala-json/

Используя классы case и Play WS (уже включенные в Play Framework), вы конвертируете классы json и case с помощью простого неявного однострочного

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

object User {
  implicit val userJsonFormat = Json.format[User]
}
pedrorijo91
источник