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文档。