Scala 2.10 + Json序列化和反序列化
斯卡拉2.10似乎已经打破了一些老图书馆(至less目前)像jackson和电梯。
目标可用性如下:
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)
但是我很难find现有的生成和反序列化JSON的方法,这些方法和Scala 2.10一起工作。
在Scala 2.10中有最好的做法吗?
Jackson是一个快速处理JSON的Java库。 Jerkson项目包装jackson,但似乎被放弃。 我已经转换到jackson的Scala模块序列化和反序列化到本地Scala数据结构。
为了得到它,请在build.sbt
包含以下build.sbt
:
libraryDependencies ++= Seq( "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.1.3", ... )
然后你的例子将工作逐字与下面的jackson包装(我从jackson模块斯卡拉testing文件中提取):
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选项包括基于Programming Scala书籍的Twitter scala-json – 这很简单,但是要牺牲性能。 还有spray-json ,它使用parboiled进行parsing。 最后, Play的JSON处理看起来不错,但不容易从Play项目解耦。
提到json4s包装jackson,lift-json或自己的本地实现作为一个长期的解决scheme:
- 码
- 网站
我可以衷心推荐在斯卡拉json支持的argonaut 。 所有你需要configuration它来序列化你的Customer对象是一行:
implicit lazy val CodecCustomer: CodecJson[Customer] = casecodec6(Customer.apply, Customer.unapply)("id","name","address","city","state","user_id")
这将皮条客您的类给它一个.asJson
方法,把它变成一个string。 它也将pimpstring类给它一个方法.decodeOption[List[Customer]]
来parsingstring。 它处理您的类罚款的选项。 这里有一个工作课,通过testing和运行的主要方法,你可以放入一个混帐的克隆的argonaut看到它一切工作正常:
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}") } }
开发人员也有帮助和响应人们入门。
现在有一个Jerkson的分支在https://github.com/randhindi/jerkson支持Scala 2.10。
所以,基于没有错误信息和不正确的示例代码,我怀疑这是更多的只是不理解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]
如果这不是你遇到麻烦的部分,那么请让我知道,我可以尝试修改我的答案,使其更有帮助。