spray-json

spray-json是一個輕量級的,簡介的和高效的使用Scala實現的jsongit

它擁有如下特徵:github

    • 一個簡單不可變的模型的json語言元素
    • 一個高效的json解析器
    • 可選擇既緊湊又漂亮的json到string的打印(格式化輸出)
    • 基於類的自定義對象的(反)序列化(沒有反射,沒有入侵)
    • 沒有外部依賴包

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._ //若是你不提供本身的協議(見下文)

以下樣例:

  • 解析JSON字符串轉換爲樹結構(Abstract Syntax Tree (AST))實例
val source = """{ "some": "JSON source" }"""
val jsonAst = source.parseJson // or JsonParser(source)

輸出:

source: String = { "some": "JSON source" }
jsonAst: spray.json.JsValue = {"some":"JSON source"}
  • 打印JSON AST 返回一個string既能夠用CompactPrinter也能夠用PrettyPrinter輸出
val json = jsonAst.prettyPrint //格式化輸出
val json1 = jsonAst.compactPrint //輸出一行

輸出:

json: String = {
  "some": "JSON source"
}
json1: String = {"some":"JSON source"}
  • 調用其toJson方法將scala的任意類型轉換爲一個Json AST
val jsonAst = List(1, 2, 3).toJson

輸出:

jsonAst: spray.json.JsValue = [1,2,3]
  • 調用convertTo方法將JSON AST 轉換爲Scala object
val jsonAst = List(1, 2, 3).toJson
jsonAst.convertTo[List[Int]]

輸出:

res0: List[Int] = List(1, 2, 3)

爲了使對象的步驟3和步驟4的工做你須要指定隱式類型的值的範圍,提供JsonFormat[T]實例爲T,T(直接或間接)所使用的全部類型。

 

JsonProtocol

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使用:

  • Byte, Short, Int, Long, Float, Double, Char, Unit, Boolean
  • String, Symbol
  • BigInt, BigDecimal
  • Option, Either, Tuple1 - Tuple7
  • List, Array
  • immutable.{Map, Iterable, Seq, IndexedSeq, LinearSeq, Set, Vector}
  • collection.{Iterable, Seq, IndexedSeq, LinearSeq, Set}
  • JsValue

大多數狀況下你也想不經過DefaultJsonProtocol轉換類型,在這些狀況下你須要提供JsonFormat[T]爲您的自定義類型。這並不難。

提供 JsonFormats 的 Case 類

若是您的自定義類型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

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

JsonFormat 和 RootJsonFormat比較

根據JSON規範並非全部容許定義JSON值類型的根級別的一個JSON文檔。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息