37

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 中是否有这样做的最佳实践方法?

4

5 回答 5

39

Jackson是一个快速处理 JSON 的 Java 库。Jerkson 项目包含了杰克逊,但似乎被放弃了。我已切换到 Jackson 的Scala 模块,用于对原生 Scala 数据结构进行序列化和反序列化。

要获得它,请在您的 中包含以下内容build.sbt

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

然后,您的示例将使用以下 Jackson 包装器逐字运行(我从 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.runtimeClass }
    else new ParameterizedType {
      def getRawType = m.runtimeClass
      def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray
      def getOwnerType = null
    }
  }
}

其他 Scala 2.10 JSON 选项包括 Twitter 的scala-json,它基于 Programming Scala 书——它很简单,但以性能为代价。还有spray-json,它使用parboiled进行解析。最后,Play 的 JSON 处理看起来不错,但它并不容易与 Play 项目解耦。

于 2013-01-05T00:04:06.400 回答
7

提到包装 jackson、lift-json 或它自己的本机实现作为长期解决方案的json4s :

于 2013-03-05T02:12:40.907 回答
6

我可以衷心推荐argonaut在 scala 中支持 json。您只需将其配置为序列化您的 Customer 对象,只需一行:

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

这将拉皮条你的类给它一个.asJson方法,把它变成一个字符串。它还将拉皮条字符串类给它一个.decodeOption[List[Customer]]解析字符串的方法。它可以很好地处理您班级中的选项。这是一个通过测试的工作类和一个正在运行的 main 方法,您可以将其放入 argonaut 的 git clone 中以查看它是否正常工作:

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

  }
}

开发人员也乐于助人,并且对人们入门时做出反应。

于 2013-09-07T20:39:27.053 回答
4

现在有一个支持 Scala 2.10 的 Jerkson 分支,位于https://github.com/randhindi/jerkson

于 2013-03-17T08:46:55.447 回答
2

因此,基于没有错误消息和不正确的示例代码,我怀疑这更像是一个不了解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]

如果那不是您遇到问题的部分,请告诉我,我可以尝试修改我的答案以提供更多帮助。

于 2012-10-01T03:23:09.530 回答