web-dev-qa-db-ja.com

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)

しかし、Scala 2.10で動作するJsonを生成およびデシリアライズする既存の良い方法を見つけるのに問題があります。

Scala 2.10でこれを行うベストプラクティスの方法はありますか?

36
user1698607

Jackson は、JSONを高速で処理するためのJavaライブラリです。JerksonプロジェクトはJacksonをラップしていますが、放棄されているようです。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 book--それは簡単ですが、コストがかかりますパフォーマンス。 spray-json もあり、これは解析に parboiled を使用します。最後に、 PlayのJSON処理 は見た目はいいですが、簡単には分離できません。 Playプロジェクトから。

38
Kipton Barros

Jackson、lift-json、または独自のネイティブ実装を長期的なソリューションとしてラップするjson4sに言及します。

7
Johan Prinsloo

Scalaでのjsonサポートには argonaut をお勧めします。 Customerオブジェクトをシリアル化するように設定する必要があるのは、1行だけです。

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

それはあなたのクラスに_.asJsonメソッドを文字列に変換します。また、文字列クラスをポンピングして、メソッド.decodeOption[List[Customer]]は文字列を解析します。クラスのオプションを適切に処理します。ここに、合格したテストと実行中のmainメソッドがあるワーキングクラスがあります。これらは、argautの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}")

  }
}

また、開発者は有用であり、始めようとしている人々に敏感です。

6
simbo1905

Scala 2.10 at https://github.com/randhindi/jerkson をサポートするJerksonのフォークがあります。

4

したがって、エラーメッセージと誤ったサンプルコードが存在しないことに基づいて、lift-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]

それがあなたが問題を抱えている部分ではない場合、私に知らせてください、私はより役立つように私の答えを修正しようとすることができます。

2
Matt Farmer