web-dev-qa-db-fra.com

Scala 2.10 + sérialisation et désérialisation Json

Scala 2.10 semble avoir cassé certaines des anciennes bibliothèques (au moins pour le moment) comme Jerkson et lift-json.

La convivialité cible est la suivante:

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)

Mais j'ai du mal à trouver de bonnes façons existantes de générer et de désérialiser Json qui fonctionnent avec Scala 2.10.

Existe-t-il des méthodes recommandées pour le faire dans Scala 2.10?

36
user1698607

Jackson est une bibliothèque Java pour traiter rapidement JSON. Le projet Jerkson enveloppe Jackson, mais semble abandonné. Je suis passé à Jackson Scala Module pour la sérialisation et la désérialisation vers les structures de données natives Scala.

Pour l'obtenir, incluez les éléments suivants dans votre build.sbt:

libraryDependencies ++= Seq(
  "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.1.3",
   ...
)

Ensuite, vos exemples fonctionneront textuellement avec le wrapper Jackson suivant (je l'ai extrait des fichiers de test 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
    }
  }
}

Autres Scala 2.10 Les options JSON incluent Twitter scala-json basé sur le livre de programmation Scala - c'est simple, au prix de Il y a aussi spray-json , qui utilise parboiled pour l'analyse. Enfin, la gestion JSON de Play a l'air sympa, mais il ne se dissocie pas facilement du projet Play.

38
Kipton Barros

Mentionner json4s qui encapsule jackson, lift-json ou sa propre implémentation native comme solution à long terme:

7
Johan Prinsloo

Je peux chaleureusement recommander argonaut pour le support json dans scala. Tout ce dont vous avez besoin pour le configurer pour sérialiser votre objet Client est une ligne:

implicit lazy val CodecCustomer: CodecJson[Customer] =
casecodec6(Customer.apply, Customer.unapply)("id","name","address","city","state","user_id")

Cela soutiendra votre classe pour lui donner un .asJson méthode qui le transforme en chaîne. Il va également pimp la classe de chaîne pour lui donner une méthode .decodeOption[List[Customer]] pour analyser les chaînes. Il gère très bien les options de votre classe. Voici une classe ouvrière avec un test réussi et une méthode principale en cours d'exécution que vous pouvez déposer dans un clone git d'argonaute pour tout voir fonctionner correctement:

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

  }
}

Les développeurs sont également utiles et réactifs pour les gens qui commencent.

6
simbo1905

Il existe maintenant un fork de Jerkson qui prend en charge Scala 2.10 sur https://github.com/randhindi/jerkson .

4

Donc, sur la base de l'absence d'un message d'erreur et d'un exemple de code incorrect, je soupçonne que c'est plus un problème de ne pas comprendre comment fonctionne l'extraction lift-json. Si j'ai mal compris, faites des commentaires et faites-le moi savoir. Donc, si j'ai raison, voici ce dont vous avez besoin.

Pour sérialiser:

import net.liftweb.json._
  import Extraction._

implicit val formats = DefaultFormats

case class Person(...)
val person = Person(...)
val personJson = decompose(person) // Results in a JValue

Ensuite, pour inverser le processus, vous feriez quelque chose comme:

// Person Json is a JValue here.
personJson.extract[Person]

Si ce n'est pas la partie avec laquelle vous avez des problèmes, faites-le moi savoir et je pourrai essayer de réviser ma réponse pour être plus utile.

2
Matt Farmer