Scala 2.10 + Сериализация и десериализация Json
Scala 2.10, похоже, сломал некоторые из старых библиотек (по крайней мере пока), таких как Jerkson и lift-json.
Целевая юзабилити выглядит следующим образом:
case class Person(name: String, height: String, attributes: Map[String, String], friends: List[String])
//to serialize
val person = Person("Name", ....)
val json = serialize(person)
//to deserialize
val sameperson = deserialize[Person](json)
Но мне трудно найти хорошие существующие способы генерации и десериализации Json, которые работают с Scala 2.10.
Есть ли лучшие способы сделать это в Scala 2.10?
Ответы
Ответ 1
Jackson - это библиотека Java для быстрой обработки JSON. Проект Джеркссона завершает Джексона, но, похоже, его покинули. Я переключился на Jackson Scala Module для сериализации и десериализации в собственные структуры данных Scala.
Чтобы получить его, включите следующее в build.sbt
:
libraryDependencies ++= Seq(
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.1.3",
...
)
Затем ваши примеры будут работать дословно со следующей оболочкой Джексона (я извлек ее из тестовых файлов jackson-module- scala):
import java.lang.reflect.{Type, ParameterizedType}
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.`type`.TypeReference;
object JacksonWrapper {
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
def serialize(value: Any): String = {
import java.io.StringWriter
val writer = new StringWriter()
mapper.writeValue(writer, value)
writer.toString
}
def deserialize[T: Manifest](value: String) : T =
mapper.readValue(value, typeReference[T])
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
}
}
}
Другие Scala 2.10 Параметры JSON включают Twitter scala-json на основе книги программирования Scala - это просто, за счет стоимости производительности. Существует также spray-json, в котором используется parboiled для разбора. Наконец, Воспроизведение JSON-обработки выглядит неплохо, но он не легко отделяется от проекта Play.
Ответ 2
Упоминание json4s, которое обертывает jackson, lift-json или его собственную встроенную реализацию в качестве долгосрочного решения:
Ответ 3
Я могу сердечно порекомендовать argonaut для поддержки json в scala. Все, что вам нужно для его настройки для сериализации объекта Customer, - это одна строка:
implicit lazy val CodecCustomer: CodecJson[Customer] =
casecodec6(Customer.apply, Customer.unapply)("id","name","address","city","state","user_id")
Это сутствует ваш класс, чтобы дать ему метод .asJson
, который превращает его в строку. Он также обрежет класс строки, чтобы дать ему метод .decodeOption[List[Customer]]
для синтаксического анализа строк. Он обрабатывает параметры в вашем классе. Вот рабочий класс с прохождением теста и запущенным основным методом, который вы можете добавить в клон git аргонавта, чтобы увидеть, как все это работает нормально:
package argonaut.example
import org.specs2.{ScalaCheck, Specification}
import argonaut.CodecJson
import argonaut.Argonaut._
case class Customer(id: Int, name: String, address: Option[String],
city: Option[String], state: Option[String], user_id: Int)
class CustomerExample extends Specification with ScalaCheck {
import CustomerExample.CodecCustomer
import CustomerExample.customers
def is = "Stackoverflow question 12591457 example" ^
"round trip customers to and from json strings " ! {
customers.asJson.as[List[Customer]].toOption must beSome(customers)
}
}
object CustomerExample {
implicit lazy val CodecCustomer: CodecJson[Customer] =
casecodec6(Customer.apply, Customer.unapply)("id","name","address","city","state","user_id")
val customers = List(
Customer(1,"one",Some("one street"),Some("one city"),Some("one state"),1)
, Customer(2,"two",None,Some("two city"),Some("two state"),2)
, Customer(3,"three",Some("three address"),None,Some("three state"),3)
, Customer(4,"four",Some("four address"),Some("four city"),None,4)
)
def main(args: Array[String]): Unit = {
println(s"Customers converted into json string:\n ${customers.asJson}")
val jsonString =
"""[
| {"city":"one city","name":"one","state":"one state","user_id":1,"id":1,"address":"one street"}
| ,{"city":"two city","name":"two","state":"two state","user_id":2,"id":2}
| ,{"name":"three","state":"three state","user_id":3,"id":3,"address":"three address"}
| ,{"city":"four city","name":"four","user_id":4,"id":4,"address":"four address"}
|]""".stripMargin
var parsed: Option[List[Customer]] = jsonString.decodeOption[List[Customer]]
println(s"Json string turned back into customers:\n ${parsed.get}")
}
}
Разработчики также помогают и реагируют на людей, которые начинают работать.
Ответ 4
Теперь есть вилка Джеркссона, которая поддерживает Scala 2.10 на https://github.com/randhindi/jerkson.
Ответ 5
Итак, исходя из отсутствия сообщения об ошибке и неправильного кода примера, я подозреваю, что это скорее проблема просто не понимания того, как работает лифт-json. Если я неправильно понял, сделайте комментарий и дайте мне знать. Итак, если я прав, то вот что вам нужно.
Для сериализации:
import net.liftweb.json._
import Extraction._
implicit val formats = DefaultFormats
case class Person(...)
val person = Person(...)
val personJson = decompose(person) // Results in a JValue
Затем, чтобы обратить вспять процесс, вы сделаете что-то вроде:
// Person Json is a JValue here.
personJson.extract[Person]
Если это не та часть, с которой у вас возникли проблемы, тогда дайте мне знать, и я могу попытаться пересмотреть свой ответ, чтобы быть более полезным.