基于Json进行数据传输在现在的互联网应用中已经非常非常广泛,所以了解Json数据结构是很有必要的。为了加深理解,自己动手实现一个简单的Json解析器。 实现Json解析器包括两方面: a、将Java 对象转换为Json String b、将Json String解析为Java对象
Json主要由如下两种结构和值组成: Json Object,即为键值对方式,键只能为字符串类型,值则如常规字符串,数字,日期,对象,hash表,数组,集合等等。由“{”开头,“}”结尾,内由多组键-值组成,键-值中间用“:”隔开,键值与键值之前用“,”隔开,具体如下:
<img src="http://www.json.org/object.gif"</img
Json Array,由“[”开头,“]”结尾,内由多个值组成,每个值之间用“,”隔开,具体如下:
<img src="http://www.json.org/array.gif"</img
Json Value,可以是字符串,数字,布尔,或者嵌套Json Object,Array,也可能为空,具体如下:
<img src="http://www.json.org/value.gif"</img
对于Java对象的类型,本文及其后面文章约定了几种类型的定义(可能定义有一定的局限性和不完整):
1、简单类型 a)Java的8种基本类型及其包装类型 b)Java String类型 c)继承Java Number类的类型 2、Collection类型 a)实现Java Collection接口的类型 b)继承Java Collection 接口的类型 3、Map类型 a)实现Java Map接口类型 b)继承Java Map接口的类型 4、数组类型 即Java 中定义的数组类型 5、复合类型 以上类型除外
代码见TypeUtils.java:
/*
* 即 boolean、byte、char、short、int、long、float 和 double
* @see Class.isPrimitive()
*/
public static boolean isPrimitiveType(ClassJava 对象转Json String大体流程如下:
1、对于输入的Java对象实例,首先判断是属于那种类型,然后根据不同类型分别进行处理,处理简单类型,其它都是需要进行嵌套处理,对于Map,集合,数组类型,还需要循环嵌套处理,最终底层来看都是根据简单类型进行处理,然后将处理结果统一到一个StringBuilder中返回。
2、简单类型处理,对应Json Value,直接将简单类型转换为String类型,然后返回。
3、复合类型处理,对应Json Object,这里只能处理pojo类,其它不符合该要求的,将无法解析。通过判断对象实例的getter,setter获取对应的字段名称,也即为key,然后通过getter方法获取值,再对值回到1中嵌套解析处理。
4、Map类型处理,也是对应Json Object,这里的Map中的key对应着Json key,通过循环迭代获取值,再对值回到1中嵌套解析处理。
5、数组/集合类型处理,也是对应Json Array,通过循环迭代获取值,再对值回到1中嵌套解析处理。
最后再将结果返回即可。
代码参考Json.java:
/* 将类转换为json格式字符串
*/
public static String toJsonString(Object jsonObj) {
if (jsonObj == null) {
return null;
}
ClassJsonObject实际就是对应Json结构,val-Json Value(val只能是Java String,Java Map,Java Lis,其中Map-Json Object,List-Json Array),key- Json key三种结构,由于是嵌套的,所以还定义了一个parent,具体见Json#JsonObject.java:
将Json String解析为JsonObject流程图:
最终解析出来的是一个JsonObject对象实例,该对象实例中又包含了子JsonObject,就像一个树结构,具体代码如下:
private static JsonObject toJsonObject(String jsonStr) {
if (CommonUtils.isEmpty(jsonStr)) {
return null;
}
JsonObject jb = null;
StringBuilder sbd = new StringBuilder();
char[] jcs = jsonStr.toCharArray();
int jLen = jcs.length;
String key = null;
String val = null;
Object jVal = null;
char jc;
for (int index = 0; index < jLen; index++) {
jc = jcs[index];
if (jc == '{') {
// 初始化为Map
jb = new JsonObject(jb, key, new HashMap
将Java JsonObject类解析为Java对象实例
这里会有两个参数,一个是Java JsonObject实例值,一个是目标Java对象class,转换后的结果是目标Java对象实例。如《Java实现一个简单的Json解析器(一)》提到的本文的Java对象类型分类,分别对目标Java对象的类型进行判断,根据不同类型,分别做不同的类型解析处理,解析流程如下:
<img src="JavaParse.png"</img
有几个地方需要重点说明一下:
1、整个解析过程是嵌套执行,目标Java对象的类型和JsonObject对象的类型能对应上才能解析,否则可能被丢弃,对应关系大体如下:
(1)目标Java对象为简单类型,则JsonObject对象的值可以为任意类型,但解析是强制转换为String再进行解析。
(2)目标Java对象为复合或者Map类型,则JsonObject对象的值只能为Map类型。
(3)目标Java对象为集合或者数组类型,则JsonObject对象的值只能为集合类型。
2、对于目标Java对象为非简单类型时,需要判断出pojo类中的字段,或者Map,数组,集合中定义的值对应哪个Java类(比如byte[String],则定义的值为String.class类,又比如Map<String,TestDto,则定义的值为TestDto.class类,若无法确定,则取默认的Java的Object.class),以便作为新的目标Java对象进行嵌套解析,最终最底层都是调用简单类型进行处理,具体代码见如下:
3、对于目标Java对象中有些字段使用接口进行定义,若无法找到具体的实现类时,则通过Java代理实现setter和getter方法,代码实现如下:
static class JsonInvocationHandler implements InvocationHandler {
private Map srcVals = null;
private Map
1、日期(格式)处理
2、数值的处理,如科学计数法转换等
3、字符串编码处理,避免出现解析或者转换的乱码
4、格式化输出处理
5、性能和容错处理
总结
1、理解Json数据结构基础上,通过与Java语言特性进行对应,实现Json解析器功能
2、划分类型,针对不同类型进行不同的处理,类型最终处理都归结为简单类型的处理
3、针对复合类型处理,需化繁为简进行处理
4、针对集合或者Map类型处理,首先要能够提取集合中对象的类型或者值,然后进行循环处理
5、理解代理实现类
参考
Json介绍:http://www.json.org/
阿里巴巴Fastjson:https://fastjson.codeplex.com/