Какую библиотеку JSON использовать в Scala?
Мне нужно построить строку 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 += ...
Какая библиотека / решение ближе всего к этому?
15 ответов
К сожалению, написание библиотеки JSON является версией сообщества Scala для кодирования приложения со списком задач.
Есть довольно много альтернатив. Я перечисляю их в произвольном порядке, с примечаниями:
- parsing.json.JSON - Предупреждение о том, что эта библиотека доступна только до версии Scala 2.9.x (удалено в более новых версиях)
- Spray -JSON - Извлечено из проекта Spray
- Jerkson ± - Предупреждение о хорошей библиотеке (построенной на основе Java Джексона), но теперь оставленной. Если вы собираетесь использовать это, вероятно, следуйте примеру проекта Scalding и используйте форк backchat.io
- sjson- Дебасиш Гош
- Лифт-JSON- Может использоваться отдельно от проекта Лифт
- json4s§ ± - Извлечение из lift-json, которое пытается создать стандартную JSON AST, которую могут использовать другие библиотеки JSON. Включает поддержку Джексона
- Argonaut§ - FP-ориентированная JSON-библиотека для Scala, созданная Scalaz
- play-json± - теперь доступен отдельно, подробности смотрите в этом ответе
- дижон -предупреждение оставлено. Динамически типизированная библиотека Scala JSON
- sonofjson- библиотека JSON, нацеленная на супер-простой API
- Jawn- библиотека JSON от Эрика Осхайма, нацеленная на скорость Джексона или выше
- Rapture JSON± - интерфейс JSON, который может использовать 2, 4, 5, 6, 7, 11 или Джексона в качестве серверных
- Цирцея - вилка Аргонавта, построенная на вершине кошки вместо скалаза
- jsoniter-scala- макросы Scala для генерации сверхбыстрых кодеков JSON во время компиляции
§ = имеет интеграцию Скалаза, ± = поддерживает взаимодействие с ДжексономJsonNode
В Snowplow мы используем json4s с серверной частью Джексона; у нас тоже был хороший опыт с Argonaut.
Lift-json имеет версию 2.6 и работает очень хорошо (и также очень хорошо поддерживается, сопровождающий всегда готов исправить любые ошибки, которые могут найти пользователи. Вы можете найти примеры, использующие его, в репозитории github
Сопровождающий (Джони Фриман) всегда доступен в списке рассылки Lift. В списке рассылки есть и другие пользователи, которые также очень полезны.
Как указывает @Alexey, если вы хотите использовать библиотеку с другой версией Scala, скажите 2.11.x
, менять scalaVersion
и использовать %%
следующее:
scalaVersion := "2.11.5"
"net.liftweb" %% "lift-json" % "2.6"
Вы можете проверить сайт http://liftweb.net/, чтобы узнать последнюю версию с течением времени.
Я предлагаю использовать 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"}]
Номер 7 в списке - Джексон, не использующий Джексона. Он поддерживает объекты Scala (классы дел и т. Д.).
Ниже приведен пример того, как я его использую.
object MyJacksonMapper extends JacksonMapper
val jsonString = MyJacksonMapper.serializeJson(myObject)
val myNewObject = MyJacksonMapper.deserializeJson[MyCaseClass](jsonString)
Это делает это очень просто. Кроме того, XmlSerializer и поддержка JAXB Annotations очень удобны.
В этом сообщении блога описывается его использование с аннотациями JAXB и платформой 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
}
}
}
Может быть, я немного опоздал, но вы действительно должны попробовать использовать библиотеку 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-snapshot.
Вот базовая реализация написания, а затем чтения 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)
}
}
Вы должны проверить Генсона. Это просто работает и намного проще в использовании, чем большинство существующих альтернатив в Scala. Он быстрый, имеет множество функций и интеграций с некоторыми другими библиотеками (jodatime, json4s DOM api...).
И все это без какого-либо необычного ненужного кода, такого как импликации, пользовательские программы чтения / записи для базовых случаев, неиспользуемый 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, но это не значит, что я не объективен:)
Jawn - очень гибкая библиотека JSON-анализатора в Scala. Это также позволяет создавать собственные AST; вам просто нужно снабдить его небольшой чертой, чтобы сопоставить его с AST.
Отлично работал для недавнего проекта, который нуждался в небольшом разборе JSON.
Восхищение, похоже, отсутствует в списке ответов. Его можно получить по http://rapture.io/ и позволяет вам (помимо всего прочего):
- выберите JSON back-end, что очень полезно, если вы уже используете его (при импорте)
- решить, работаете ли вы с Try, Future, Option, Either и т. д. (также в режиме импорта)
- сделать много работы в одной строке кода.
Я не хочу копировать / вставлять примеры Rapture со своей страницы. Хорошая презентация о возможностях Rapture была представлена Джоном Pretty на SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI
Ответ @ 7 от AlaxDean, Argonaut - единственный, с которым мне удалось быстро поработать с sbt и intellij. На самом деле json4s также занял мало времени, но иметь дело с необработанным AST - не то, что я хотел. Я заставил аргонавта работать, поместив одну строку в мой 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, который является просто значением, которое также может быть нулевым (думаю, нулевым безопасным). Аргонавт использует Скалаз, поэтому, если вы видите что-то, что вы не понимаете, как символ \/
(или операция) это, вероятно, Скалаз.
Я использую uPickle, который имеет большое преимущество в том, что он будет автоматически обрабатывать вложенные классы:
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"
Вы можете попробовать это: 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)
}
Play выпустила свой модуль для работы с JSON независимо от Play Framework, Play WS
Сделал сообщение в блоге об этом, проверьте это в http://pedrorijo.com/blog/scala-json/
Используя case-классы и Play WS (уже включены в Play Framework), вы конвертируете case-классы между json и case-классами, используя неявную однострочную строку
case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)
object User {
implicit val userJsonFormat = Json.format[User]
}
Я использую библиотеку 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/
Позвольте мне также дать вам версию SON of JSON:
import nl.typeset.sonofjson._
arr(
obj(id = 1, name = "John)
obj(id = 2, name = "Dani)
)