spray-json


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

它擁有以下特征:

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

spray可以做以下轉換:

*JSON字符串

*基於JsValue的JSON抽象語法樹(JSON Abstract Syntax Tree(ASTs))

*任意的scala類型的實例

如下圖描述

安裝

spray-json 可以從 http://repo.spray.io/倉庫獲得

最終的發布版本是1.3.2 ,對應的構建在scala 2.10.5和scala 2.11.6

如果你使用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文檔。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM