spray-json是一個輕量級的,簡介的和高效的使用Scala實現的jsongit
它擁有如下特徵:github
spray能夠作如下轉換:json
*JSON字符串app
*基於JsValue的JSON抽象語法樹(JSON Abstract Syntax Tree(ASTs))編輯器
*任意的scala類型的實例jsonp
以下圖描述spa
spray-json 能夠從 http://repo.spray.io/倉庫得到scala
最終的發佈版本是1.3.2 ,對應的構建在scala 2.10.5和scala 2.11.6orm
若是你使用SBT 使用下面方依賴將spray-json加入到你的項目中對象
libraryDependencies += "io.spray" %% "spray-json" % "1.3.2"
使用方法
spray-json 很是容易使用.
僅僅須要導入相關方法
import spray.json._ import DefaultJsonProtocol._ //若是你不提供本身的協議(見下文)
以下樣例:
val source = """{ "some": "JSON source" }""" val jsonAst = source.parseJson // or JsonParser(source)
輸出:
source: String = { "some": "JSON source" } jsonAst: spray.json.JsValue = {"some":"JSON source"}
val json = jsonAst.prettyPrint //格式化輸出
val json1 = jsonAst.compactPrint //輸出一行
輸出:
json: String = { "some": "JSON source" } json1: String = {"some":"JSON source"}
val jsonAst = List(1, 2, 3).toJson
輸出:
jsonAst: spray.json.JsValue = [1,2,3]
val jsonAst = List(1, 2, 3).toJson jsonAst.convertTo[List[Int]]
輸出:
res0: List[Int] = List(1, 2, 3)
爲了使對象的步驟3和步驟4的工做你須要指定隱式類型的值的範圍,提供JsonFormat[T]實例爲T,T(直接或間接)所使用的全部類型。
spray-json使用的是SJSON(https://github.com/debasishg/sjs)基於類類型的scala習慣的方法鏈接一個已經存在的類型T,依據的邏輯爲:怎樣序列化實例到Json和從Json反序列化到實例。(事實上,spray-json甚至從新使用SJSON的代碼,參照‘Credits’這一節)
這個方法有個優勢就是不不須要改變(或者訪問)T的資源代碼。全部的(反)序列化都是"從外面"附加的.他沒有涉及到反射,因此結果轉換快。
Scala的優秀類型推斷減少了冗餘和引用,scala編輯器當確認編譯時你必須提供全部的序列化和反序列化的邏輯。
在spray-json的術語中一個'JsonProtocol' 是沒有任何東西的,可是一堆類型爲JsonFormat[T]隱式(implicit)的值,其中每個JsonFormat[T]包含怎樣從JSON轉換實例化的T。全部的JsonFormat 是一個協議須要是"mece"(相互排斥的,徹底窮盡的(mutually exclusive, collectively exhaustive)),例如:他們不須要重疊在一塊兒,須要被應用程序跨越類型。
這些聽起來比如今的更復雜。
spray-json來自一個DefaultJsonProtocol,已經封裝了全部的Scala值類型,以及最重要的參考和集合類型。 只要你的代碼沒有超過這些內容就須要使用DefaultJsonProtocol
下面的類型已經被DefaultJsonProtocol使用:
大多數狀況下你也想不經過DefaultJsonProtocol轉換類型,在這些狀況下你須要提供JsonFormat[T]爲您的自定義類型。這並不難。
若是您的自定義類型T是一個case類,爲DefaultJsonProtocol增長JsonFormat[T]很容易:
case class Color(name: String, red: Int, green: Int, blue: Int) object MyJsonProtocol extends DefaultJsonProtocol { implicit val colorFormat = jsonFormat4(Color) } import MyJsonProtocol._ import spray.json._ val json = Color("CadetBlue", 95, 158, 160).toJson val color = json.convertTo[Color]
運行結果:
defined class Color defined module MyJsonProtocol import MyJsonProtocol._ import spray.json._ json: spray.json.JsValue = {"name":"CadetBlue","red":95,"green":158,"blue":160} color: Color = Color(CadetBlue,95,158,160)
提供JsonFormat的case 類
若是你的自定義類型是一個case class 爲JsonFormat[T]增長一個DefaultJsonProtocol是很是容易的:
case class Color(name: String, red: Int, green: Int, blue: Int) object MyJsonProtocol extends DefaultJsonProtocol { implicit val colorFormat = jsonFormat4(Color) } import MyJsonProtocol._ import spray.json._
val json = Color("CadetBlue", 95, 158, 160).toJson val color = json.convertTo[Color]
運行結果:
import MyJsonProtocol._ import spray.json._ json: spray.json.JsValue = {"name":"CadetBlue","red":95,"green":158,"blue":160} color: Color = Color(CadetBlue,95,158,160)
jsonFormatX方法將模板減少爲最小,僅僅須要傳遞一個case class 的伴生對象,他就能夠返回一個現成的JsonFormatle類型(正確的匹配參數的數量是你的case class 類例如:你的case class 有13個字段 你須要使用JsonFormat13 這個方法).
jsonFormatX 方法嘗試屢次調用JsonFormat的重載方法提取你的case class中定義的參數,這個你必須手動指定字段名。
假如spray-json沒法肯定字段類型,或者你的JSON Object 使用成員名稱月case class中的名稱不相同也能直接使用JsonFormat。
有一個其餘的習慣:若是你明確的指明瞭clase class的伴生對象上面的操做將中止工做。你必須顯式地引用伴生對象
case class Color(name: String, red: Int, green: Int, blue: Int) object Color object MyJsonProtocol extends DefaultJsonProtocol { implicit val colorFormat = jsonFormat4(Color.apply) }
運行結果:
import spray.json._ defined class Color defined module Color defined module MyJsonProtocol
若是你的case類是通用的,它須要類型參數自己jsonFormat方法也能夠幫助你。
然而,有模板有一點要求,你須要爲參數添加上下文和顯示的引用case class類的apply方法,例以下面的例子:
case class NamedList[A](name: String, items: List[A]) object MyJsonProtocol extends DefaultJsonProtocol { implicit def namedListFormat[A :JsonFormat] = jsonFormat2(NamedList.apply[A]) }
運行結果:
import spray.json._ defined class NamedList defined module MyJsonProtocol
NullOptions特徵提供的另外一種呈現模式可選的類成員。未定義的成員是沒法提取出來的。
JsonProtocol爲你定義了未定義程序最爲null(主意這僅僅是JSON的寫法,spray-json常常讀取錯誤的操做程序做爲null ).
爲其餘類型提供JsonFormat
固然你也能用序列化和反序列化的不是case class類的類型邏輯。
這是一個方法:
import spray.json._
import DefaultJsonProtocol._
class Color(val name: String, val red: Int, val green: Int, val blue: Int)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ColorJsonFormat extends RootJsonFormat[Color] {
def write(c: Color) = JsArray(JsString(c.name), JsNumber(c.red), JsNumber(c.green), JsNumber(c.blue))
def read(value: JsValue) = value match {
case JsArray(Vector(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue))) =>
new Color(name, red.toInt, green.toInt, blue.toInt)
case _ => deserializationError("Color expected")
}
}
}
import MyJsonProtocol._
val json =new Color("CadetBlue", 95, 158, 160).toJson
val color = json.convertTo[Color]
color.blue
運行結果
import spray.json._ import spray.json.DefaultJsonProtocol._ defined class Color defined module MyJsonProtocol import MyJsonProtocol._ json: spray.json.JsValue = ["CadetBlue",95,158,160] color: Color = Color@74ba1505
res0: Int = 160
這個序列化的Color實例做爲一個JSONArray,緊湊但語義元素不明確。
另外一種方式將JSON對象序列化的Color:
import spray.json._
import DefaultJsonProtocol._
class Color(val name: String, val red: Int, val green: Int, val blue: Int)
object MyJsonProtocol extends DefaultJsonProtocol { implicit object ColorJsonFormat extends RootJsonFormat[Color] { def write(c: Color) = JsObject( "name" -> JsString(c.name), "red" -> JsNumber(c.red), "green" -> JsNumber(c.green), "blue" -> JsNumber(c.blue) ) def read(value: JsValue) = { value.asJsObject.getFields("name", "red", "green", "blue") match { case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue)) => new Color(name, red.toInt, green.toInt, blue.toInt) case _ => throw new DeserializationException("Color expected") } } } }
這是一個更詳細的定義和生成的JSON但傳輸到該領域語義JSON。注意這個方法僅僅使用月spray-json對case class
根據JSON規範並非全部容許定義JSON值類型的根級別的一個JSON文檔。