【问题标题】:Scala 2.10 + Json serialization and deserializationScala 2.10 + Json 序列化和反序列化
【发布时间】:2012-09-17 11:20:39
【问题描述】:

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 中有最佳实践方法吗?

【问题讨论】:

    标签: json scala scala-2.10 lift-json


    【解决方案1】:

    Jackson 是一个快速处理 JSON 的 Java 库。 Jerkson 项目包含了杰克逊,但似乎被放弃了。我已切换到 Jackson 的 Scala Module 进行序列化和反序列化为原生 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's JSON handling 看起来不错,但它并不容易与 Play 项目解耦。

    【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      我可以衷心推荐 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 克隆中以查看它是否正常工作:

      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 的 Jerkson 分支https://github.com/randhindi/jerkson。

        【讨论】:

        • 如何在 IntelliJ Idea 12 中安装和使用?
        • 恐怕无法为您提供帮助。我最终选择了 spray-json 而不是 jerkson。
        • 没关系,你是怎么安装的?
        • 我从来没有安装过jerkson,只是注意到那里有一个更新的版本:)。如果你指的是 spray-json,我只是指出它是一个 sbt 依赖项。
        • 安装是什么意思?如果您使用某种依赖管理构建工具,您只需将其添加为依赖。 sbt,安装下见github.com/spray/spray-json。
        【解决方案5】:

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

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

        【讨论】:

        • 我认为问题在于 Scala 2.10 破坏了二进制兼容性,并且 lift-json 目前不是最新的。
        • lift-json for 2.10 现在可用并且是最新的!现在对我来说工作得很好。看到这个:liftweb.net/25
        猜你喜欢
        • 2013-04-04
        • 1970-01-01
        • 2014-07-02
        • 2015-02-28
        • 2020-10-23
        • 2013-06-19
        • 1970-01-01
        • 2019-12-24
        • 1970-01-01
        相关资源
        最近更新 更多