geotrellis使用(十九)spray-json框架介绍
Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html
目录
一、前言
Json作为目前最流行的数据交换格式,具有众多优势,在Scala语言中以及当我们使用Geotrellis前后台交换数据的时候都少不了要使用Json,本文为大家介绍一款开源的Json处理框架——spray-json。
二、spray-json简介
spray-json是一款使用Scala语言编写的开源Json处理框架。GitHub地址:https://github.com/spray/spray-json。其中对其介绍如下:
spray-json is a lightweight, clean and efficient JSON implementation in Scala.
It sports the following features:
A simple immutable model of the JSON language elements
An efficient JSON parser
Choice of either compact or pretty JSON-to-string printing
Type-class based (de)serialization of custom objects (no reflection, no intrusion)
No external dependencies
spray-json allows you to convert between
String JSON documents
JSON Abstract Syntax Trees (ASTs) with base type JsValue
instances of arbitrary Scala types
大意就是spray-json轻量、无依赖、高效,没有使用反射等。可以在JSON字符串对象、AST(JSON树)对象、Scala类型之间任意转换。
在Scala程序中使用spray-json,只需要在build.sbt文件中添加libraryDependencies += "io.spray" %% "spray-json" % "1.3.2",然后更新sbt即可。
三、spray-json使用
总体上使用spray-json需要先定义一个转换的协议(Protocol),该协议指定了如何在Scala对象与JOSN对象之间进行转换。spary-json也提供了一些基础类型的转换协议,在DefaultJsonProtocol类中。
3.1 基础类型转换
首先引入spray-json以及DefaultJsonProtocol
import spray.json._
import DefaultJsonProtocol._
然后可以直接进行类型转换,代码如下:
val str = """{"name":"wsf", "age":26}"""
val json: JsValue = str.toJson
val json2 = str.parseJson
println(json2.prettyPrint)
println(json2.compactPrint)
val age = 26
val json_age = age.toJson
json_age.convertTo[Int]
使用toJson和parseJson都能将字符串或其他类型转换成JsValue,prettyPrint是将json以分行的方式优雅的输出,compactPrint直接在一行压缩输出,convertTo可以直接将json对象转为Scala对应的类型。
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
3.2 case class类型转换
如果不在DefaultJsonProtocol支持的数据类型中就需要我们自己定义JsonProtocol,最简单的类型是case class,其方法如下:
case class MyInt(value: Int)
object MyIntProtocol extends DefaultJsonProtocol {
implicit val format = jsonFormat1(MyInt)
}
import MyIntProtocol._
val json2 = MyInt(10).toJson
println(json2)
val myInt = json2.convertTo[MyInt]
println(myInt)
简单的说就是定义一个object类,并添加一个隐式参数,参数的值为jsonFormatX(X表示数字)函数将自定义的case类传入。
这里需要说明的是自定义的case类有几个属性这里X就为几,即调用相应的函数。如果case类还定义了伴随的object类,那么jsonFormatX函数就需要传入MyInt.apply。并且MyIntProtocol类的定义不能放在调用位置的后面,否则会出错。
3.3 包含泛型的类型转换
如果case类的属性中包含了泛型那么实现方法稍有不同,代码如下:
case class MyList[A](name: String, items: List[A])
object MyListProtocol extends DefaultJsonProtocol {
implicit def myListFormat[A: JsonFormat] = jsonFormat2(MyList.apply[A])
}
import MyListProtocol._
val json3 = MyList[Int]("wsf", List(1, 2, 3)).toJson
println(json3.prettyPrint)
val myList = json3.convertTo[MyList[Int]]
println(myList)
同样是定义一个object类,并添加一个隐式函数,不同的是传入的是MyList.apply[A],即apply加泛型,并且需要指明返回类型为[A: JsonFormat]。此处还需要说明的是在基本的case类中定义隐式变量的时候用的是implicit val,而此处用的是implicit def,个人理解是在scala中变量与函数的定义比较模糊,二者基本是等价的,但是此处返回值的类型是泛型,所以要用def。
3.4 普通class类的转换
如果是一个普通的class类,就需要自己定义write和read方法。代码如下:
class Person(val name: String, val age: Int)
object MyPersonProtecol extends DefaultJsonProtocol {
implicit object myPersonFormat extends RootJsonFormat[Person] {
override def write(person: Person): JsValue = JsArray(JsString(person.name), JsNumber(person.age))
override def read(json: JsValue): Person = json match {
case JsArray(Vector(JsString(name), JsNumber(age))) => new Person(name, age.toInt)
case _ => deserializationError("Person expected")
}
}
}
import MyPersonProtecol._
val person = new Person("wsf", 26)
val json = person.toJson
println(json.prettyPrint)
val per = json.convertTo[Person]
此处相当于隐式format不在由jsonFormatX函数返回,而是自定义一个类并继承自RootJsonFormat。上述代码将Person实例转换成JsArray,既json数组对象,Person的各个属性按照定义的顺序存放到数组,同时也可以将json数组对象转换为Person实例。如果我们需要的是一个标准的json树对象而不仅仅是json数组,可以按照下述方式定义隐式对象。
implicit object myPersonFormat2 extends RootJsonFormat[Person] {
override def write(person: Person): JsValue = JsObject(
"name" -> JsString(person.name),
"age" -> JsNumber(person.age)
)
override def read(json: JsValue): Person = json.asJsObject.getFields("name", "age") match {
case Seq(JsString(name), JsNumber(age)) => new Person(name, age.toInt)
case _ => deserializationError("Person expected")
}
}
上述代码将Person对象转换成如下形式的json树对象,当然也可实现反向转换。
{
"name": "wsf",
"age": 26
}
3.5 递归类型转换
如果是case类属性又包含自身,既递归类型,在定义隐式对象的时候稍有不同,需要显式指明对象的属性,并将jsonFormat的结果传给lazyFormat,我想这里主要是为了防止递归过程中出现无限循环等错误。代码如下:
case class Foo(i: Int, foo: Option[Foo])
object myRecursiveProtocol extends DefaultJsonProtocol {
implicit val format: JsonFormat[Foo] = lazyFormat(jsonFormat(Foo, "i", "foo"))
}
import myRecursiveProtocol._
val foo: Foo = Foo(1, Some(Foo(2, Some(Foo(3, None)))))
val json = foo.toJson
println(json)
最终得到的结果如下:
{"i":1,"foo":{"i":2,"foo":{"i":3}}}
3.5 直接操作JSON对象
有时候可能我们并不需要这么复杂的功能,就想简单的拼接成JSON对象,这时候可以直接创建JsArray或者JsObject对象,按照自己的要求拼接即可。代码如下:
val json = JsArray(JsNumber(1), JsNumber(2), JsNumber(3), JsString("wsf"))
println(json)
val json2 = JsObject(
"name" -> JsString("wsf"),
"age" -> JsNumber(26)
)
println(json2)
结果如下:
[1,2,3,"wsf"]
{"name":"wsf","age":26}
四、总结
本文简单介绍了spray-json框架在处理json对象时候的一些常规操作和细节,希望能对理解json以及处理json有所帮助,并为Geotrellis中前后台数据交换等打好基础。
geotrellis使用(十九)spray-json框架介绍的更多相关文章
- 二十九、EFW框架开发的系统支持SaaS模式和实现思路
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...
- 《objective-c基础教程》学习笔记(九)—— Foundation框架介绍
在之前的博文中,我们创建的项目文件的时候,默认都有引用#import <Foundation/foundation.h> 这个头文件.但是,之前我们对Foundation都没有展开介绍.这 ...
- IOS学习之路十九(JSON与Arrays 或者 Dictionaries相互转换)
今天写了个json与Arrays 或者 Dictionaries相互转换的例子很简单: 通过 NSJSONSerialization 这个类的 dataWithJSONObject: options: ...
- Android Multimedia框架总结(十九)Camera2框架C/S模型之CameraService启动及与Client连接过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53150322 Agenda: 一 ...
- python接口自动化(十九)--Json 数据处理---实战(详解)
简介 上一篇说了关于json数据处理,是为了断言方便,这篇就带各位小伙伴实战一下.首先捋一下思路,然后根据思路一步一步的去实现和实战,不要一开始就盲目的动手和无头苍蝇一样到处乱撞,撞得头破血流后而放弃 ...
- 性能测试二十九:Dubbo框架测试脚本编写
测试脚本编写 新建一个folder命名为lib,用于存放依赖包 把以下jar全部拷进lib下,并build path 找开发要 真正要测试的以jar包形式存在的代码的类, 打开看一下 放到lib并bu ...
- 前端(十九)—— Bootstrap框架
Bootstrap Bootstrap中文文档 一.简介 Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML.CSS.JavaScrip ...
- Python爬虫(十九)_动态HTML介绍
JavaScript JavaScript是网络上最常用也是支持者对多的客户端脚本语言.它可以收集用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页游戏. 我们可以在网页源 ...
- 十九、Spring框架(注解方式测试)
一.注解方式测试 1.注解方式测试使用junit.使用junit-4.12.jar和hamcrest-all-1.3.jar(单元测试包) 把这两个jar包,导入到lib文件夹下. 2.TestSpr ...
随机推荐
- 【PostgreSQL】PostgreSQL的安装
到了新公司,新公司的数据库是使用PostgreSQL,第一次学习,第一次安装. 开始安装:
- LabVIEW 吸星大法 - 看见的好东西都是我的(中篇)
前言 写了多年的LabVIEW程序,你是否面临这样的问题 总是在做一些重复的工作,感觉很没有意思: 总在不停的写代码,做类似的控件,实现相同的功能,丝毫没有成就感: 总在天加班,没有时间去提高自己; ...
- Jtable 表格按多列排序(支持中文汉字排序)
这两天公司让做一个Jtable表格的排序,首先按A列排序,在A列相等时按B列排序,B列相等时按C列排序,ABC三列可以任意指定,最多分三列,这样的一个需求.由于我是大神,所以必须做了出来.ok,不自恋 ...
- Handlebars.js的学习
写在开头的话: 在使用Ghost搭建自己的博客的时候,发现不会Handlebars.js寸步难行,所以本人决定学习下Handlebars.js,因此在此做个记录 为什么选择Handlebars.js ...
- 【SQLServer】“无法对数据库'XXX' 执行删除,因为它正用于复制”的解决方法
从今天起,把编程中遇到的所有问题都记录下来,以便今后参考,以及方便网友查阅,希望我的问题可以帮助到很多志同道合的人们,我也是受很多前辈的提点,一步一步走来,希望大家都不要吝啬,将自己遇到的问题记录下来 ...
- bzoj 2739 最远点
Description 给你一个N个点的凸多边形,求离每一个点最远的点. Input 本题有多组数据,第一行一个数T,表示数据组数. 每组数据第一行一个数N,表示凸多边形点的个数,接下来N对数,依次表 ...
- Eclipse搭建c环境(CDT)二
Eclipse 编辑c程序环境的搭建主要为其安装CDT插件即可 Eclipse搭建CDT步骤如下: 1.首先配置好java环境,为后续运行eclipse做准备 (略) 2.下载并安装eclipse(这 ...
- 编译可在Nexus5上运行的CyanogenMod13.0 ROM(基于Android6.0)
编译可在Nexus5上运行的CyanogenMod13.0 ROM (基于Android6.0) 作者:寻禹@阿里聚安全 前言 下文中无特殊说明时CM代表CyanogenMod的缩写. 下文中说的“设 ...
- 让浏览器不再显示 https 页面中的 http 请求警报
HTTPS 是 HTTP over Secure Socket Layer,以安全为目标的 HTTP 通道,所以在 HTTPS 承载的页面上不允许出现 http 请求,一旦出现就是提示或报错: Mix ...
- 我为什么很烦在DB服务器上安装杀毒软件
常见的数据库连接问题无外乎是在数据库服务器本地可以连接SQL Server,但通过其他服务器就不可以连接.但这次我却碰到了相反的情况,在服务器本地无法通过IP/实例名连接,但从其他服务器却可以.而且每 ...