Tomjson - 一个"短小精悍"的 json 解析库

 Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符串序列化为相对应的Java对象(JavaBean)。项目地址:https://github.com/luoxn28/tomjson。关于JSON更多信息请点击JSON-百度百科

  一些有名的json序列化相关的项目有gjson、fastjson和jackjson,其中LZ使用过fastjson,另外两个没有使用过,看过一点fastjson的源码,由此产生了写一个json序列化相关库的想法,也就是现在的Tomjson。通过学习和使用Tomjson,LZ大致了解了Java类与json字符串之间的应该如何转换及代码实现。Tomjson是基于Java反射来进行序列化工作的,并不像fastjson那样可以通过ASM框架来指针每种类型生成对应的序列化类;Tomjson架构简单,理解起来较其他json序列化库相对容易一些。

  Tomjson在序列化时体现了“专人专事”的思想,比如如果是String类型的数据,则交给StringSerializer类来序列化;如果是Integer类型的数据,则交给IntegerSerializer类来处理。Tomjson在反序列化处理也是类似的,这样整体逻辑比较清晰。

1、如何使用

  下载源码导入到工程中,新建TestMain类,代码如下:

package com.luoxn28.test;

import com.luoxn28.tomjson.TomJson;
import com.luoxn28.tomjson.deserializer.JsonObject; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map; /**
* TestMain - 测试
*/
public class TestMain { public static void main(String[] args) {
Person person = new Person("luxon28", 23);
person.setMoney(13.14);
person.setDog(new Dog("gay"));
person.setDogs(new ArrayList<Dog>(Arrays.asList(new Dog("gay1"), new Dog("gar2")))); System.out.println("----- Object序列化为json -----");
String jsonString = TomJson.toJsonString(person);
System.out.println(jsonString); System.out.println("----- json序列化为Object,未提供Object类型 -----");
JsonObject jsonObject = TomJson.parseObject(jsonString);
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
System.out.print(entry.getKey() + ": " + entry.getValue() + " | ");
}
System.out.println(); System.out.println("----- json序列化为Object,提供Object类型 -----");
Person jsonPerson = TomJson.parseObject(jsonString, Person.class);
System.out.println(jsonPerson);
} }

输出结果为:

其中Person类和Dog类代码如下:

/**
* Person - 测试类
*/
public class Person { // ---------------------------------- Instance Variable private String name;
private int age;
private double money; private Dog dog;
private List<Dog> dogs = new ArrayList<>(); // ---------------------------------- Constructors public Person() { } public Person(String name, int age) {
this.name = name;
this.age = age;
} // ---------------------------------- Public Methods public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public double getMoney() {
return money;
} public void setMoney(double money) {
this.money = money;
} public Dog getDog() {
return dog;
} public void setDog(Dog dog) {
this.dog = dog;
} public List<Dog> getDogs() {
return dogs;
} public void setDogs(List<Dog> dogs) {
this.dogs = dogs;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", money=" + money +
", dog=" + dog +
", dogs=" + dogs +
'}';
} }
/**
* Dog - 测试类
*/
public class Dog { // ---------------------------------- Instance Variable private String name; // ---------------------------------- Constructors public Dog() { } public Dog(String name) {
this.name = name;
} // ---------------------------------- Public Methods public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
}

2、Tomjson架构

2.1 Tomjson特点

  • 小巧:源码中就包含4个包,deserializer包主要是一些JavaBean序列化为json字符串相关的类,serializer包主要是一些json字符串反序列化为JavaBean的类,util中有一个工具类TinyUtil.javatest是一些测试类。
  • 精悍:在小型类的序列化话速度上还是很快的 :) 。

2.2 Tomjson序列化思想

  当Java类序列化为json字符串时,通过反射获取对应Class类的各个数据域,然后获取数据域名称和值,通过写入到SerializerBuffer(封装了StringBuffer的一个类)中。主要代码如下:

// ObjectSerializer - Object序列化类
@Override
public void write(String name, Object object, SerializerBuffer buffer) {
try {
// name为null表示是Root Object
if (name == null) {
Class clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String key = field.getName();
PropertyDescriptor descriptor = new PropertyDescriptor(key, clazz);
Method method = descriptor.getReadMethod();
Object value = method.invoke(object); JsonSerializer write = config.getObject(value.getClass());
write.write(key, value, buffer);
}
}
else {
SerializerBuffer subBuffer = new SerializerBuffer(); write(null, object, subBuffer);
buffer.append(object, "\"" + name + "\":" + subBuffer.toString());
}
}
catch (Exception e) {
e.printStackTrace();
}
}

  当json字符串反序列化为Java类时,首先获取json字符串中的各个token,token也就是json字符串中的键值对,类似于"name":"luxon28"这种结构,获取token的方法如下,调用一次就可以获取到在同一层次下(也可以说在同一个类的层次)的所有token。

/**
* 获取tokens 也就是以','为分隔符把text分成多个token
* 注意:获取text中处于最上层的各个token
*/
private static List<String> getTokens(String text) {
List<String> tokens = new ArrayList<>();
Stack<Character> flag = new Stack<>(); text = text.trim();
text = TinyUtil.trimBrace(text);
for (int i = 0, length = text.length(), tokenIndex = 0; i < length; i++) {
char c = text.charAt(i);
if (c == '{' || c == '[') {
flag.push(c);
}
else if (c == '}' || c == ']') {
char tmp = flag.pop();
if (!TinyUtil.flagOk(tmp, c)) {
System.out.println("json string format error");
return new ArrayList<>();
}
} if (c == ',' && flag.size() == 0) {
tokens.add(text.substring(tokenIndex, i));
tokenIndex = i + 1;
}
else if (i == length - 1 && flag.size() == 0) {
tokens.add(text.substring(tokenIndex, length));
}
} return tokens;
}

  获取到token后,就可以单独分析每一个token了,可以把token看成一个键值对,也就是"name":"luxon28"这种结构。如果值是由""所包围的,则该值就是String类型的,如果该值没有被""所包围,则表示是数值类型的,再根据具体数值类型判断是Integer还是Double类型。相关代码如下:

/**
* 解析json字符串,将结果存放到clazz实例中
*/
public static <T> T parseObject(String text, Class<T> clazz) {
List<String> tokens = getTokens(text);
JsonObject jsonObject = new JsonObject(); for (String token : tokens) {
if (TinyUtil.isBeanKeyValue(token)) {
parse(token, jsonObject.keyValue);
}
else if (TinyUtil.isJsonBean(token)) {
String key = TinyUtil.getJsonKey(token);
String valueStr = TinyUtil.getJsonValue(token); Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
if (name.equals(key)) {
String type = field.getGenericType().toString();
String className = type.substring(type.indexOf(' ') + 1, type.length());
Class subClazz = null;
try {
subClazz = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
// break for (Field field : fields)
break;
} try {
Object subObject = subClazz.newInstance();
subObject = parseObject(valueStr, subClazz);
jsonObject.keyValue.put(key, subObject);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
else if (TinyUtil.isJsonCollectionBean(token)) {
String key = TinyUtil.getJsonKey(token);
String valueStr = TinyUtil.getJsonValue(token); Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
if (name.equals(key)) {
String type = field.getGenericType().toString();
String valueClass = type.substring(type.indexOf('<') + 1, type.indexOf('>')); List list = new ArrayList<>();
List<String> beans = getTokens("{" + TinyUtil.trimSquare(valueStr) + "}");
for (String bean : beans) {
Class subClazz = null;
try {
subClazz = Class.forName(valueClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
break;
} Object subObject = parseObject(bean, subClazz);
list.add(subObject);
}
jsonObject.keyValue.put(TinyUtil.getJsonKey(token), list);
}
}
}
else {
System.out.println("I don't know how to do it :(");
}
} T object = null; try {
object = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
PropertyDescriptor descriptor = new PropertyDescriptor(name, clazz);
Method method = descriptor.getWriteMethod(); if (jsonObject.keyValue.containsKey(name)) {
Object arg = jsonObject.keyValue.get(name);
method.invoke(object, arg);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
return object;
}
}

2.3 Tomjson源码分析

  Tomjson的口点是TomJson类,TomJson的toJsonString()方法是将Java类序列化为json字符串,parseObject()方法是将json字符串反序列化为Java类,其返回JsonObject类型或者Java类类型,如果给parseObject()方法传递类类型的话。

  SerializerContext和DeserializerContext是tomjson的配置类,其中SerializerContext存放的是关于Java类序列化为json字符串的配置,也就是Class类型与json序列化类映射关系,DeserializerContext存放的是关于json字符串反序列化为Java类的配置,也就是Class类型与json反序列化类映射关系。

TomJson类

public class TomJson {

    // serializer配置类
private static SerializerContext config = SerializerContext.instance(); // ---------------------------------- Public Methods /**
* Object转换为json字符串
*/
public static String toJsonString(Object object) {
SerializerBuffer buffer = new SerializerBuffer(); JsonSerializer write = config.getObject(object.getClass());
write.write(null, object, buffer);
return buffer.toString();
} /**
* json字符串转换为JsonObject
*/
public static JsonObject parseObject(String text) {
return JsonObject.parseObject(text);
} /**
* json字符串转换为指定的Object
*/
public static <T> T parseObject(String text, Class<T> clazz) {
return JsonObject.parseObject(text, clazz);
} }

SerializerContext类

public class SerializerContext {

    // 存放Class类型与json序列化类映射关系
private static Map<Class, JsonSerializer> config = null; // objectSerializer序列化类
private static ObjectSerializer objectSerializer = null;
// Collection序列化类
private static CollectionSerializer collectionSerializer = null; static {
config = new HashMap<Class, JsonSerializer>(); config.put(String.class, new StringSerializer()); config.put(Boolean.class, new BooleanSerializer());
config.put(Integer.class, new IntegerSerializer());
config.put(Long.class, new LongSerializer());
config.put(Double.class, new DoubleSerializer()); } // ... }

DeserializerContext类

public class DeserializerContext {

    private static DeserializerContext context = new DeserializerContext();

    // 存放Class类型与json反序列化类映射关系
private static Map<Class, JsonDeserializer> config = null; static {
config = new HashMap<Class, JsonDeserializer>(); config.put(String.class, new StringDeserializer());
config.put(Integer.class, new IntegerDeserializer());
config.put(Long.class, new LongDeserializer());
config.put(Double.class, new DoubleDeserializer());
} // ... }

参考:

  1、项目地址:https://github.com/luoxn28/tomjson

  2、fastjson:https://github.com/alibaba/fastjson

 

Tomjson - json 解析库的更多相关文章

  1. Tomjson - 一个"短小精悍"的 json 解析库

    Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...

  2. fastjson是阿里巴巴的开源JSON解析库

    fastjson的API十分简洁. String text = JSON.toJSONString(obj); //序列化 VO vo = JSON.parseObject("{...}&q ...

  3. python 中的json解析库

    当一个json 数据很大的时候.load起来是很耗时的.python中常见的json解析库有cjson,simplesjson,json, 初步比较了一下, 对于loads来讲 simplejson ...

  4. C++的Json解析库:jsoncpp和boost

    C++的Json解析库:jsoncpp和boost - hzyong_c的专栏 - 博客频道 - CSDN.NET C++的Json解析库:jsoncpp和boost 分类: 网络编程 开源库 201 ...

  5. Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例

    Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例 继上篇json解析,我用了原生的json解析,但是在有些情况下我们不得不承认,一些优秀的json解析框架确实十分的 ...

  6. C++的Json解析库:jsoncpp和boost(转)

    原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...

  7. 常用json解析库比较及选择 fastjson & gson

    一.常用json解析库比较及选择 1.简介 fastjson和gson是目前比较常用的json解析库,并且现在我们项目代码中,也在使用这两个解析库. fastjson 是由阿里开发的,号称是处理jso ...

  8. [转]C++的Json解析库:jsoncpp和boost

    JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...

  9. 深入 Go 中各个高性能 JSON 解析库

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/535 其实本来我是没打算去看 JSON 库的性能问题的,但是最近我对 ...

随机推荐

  1. 智能电视TV开发---如何实现程序省电

    对于很多使用智能手机的用户来,很多抱怨手机耗电太快,很多人买手机的时候卖家都是推荐买两块电池,还有如果用户留心的话,在买手机的网页上,卖家会显示播放视频多长时间,听音乐多长时间,待机多长时间,不过看的 ...

  2. Linux内核目录解析~

    以前进过一些公司看到一些服务器,把环境搭建都搭建在etc里面,而且都乱套了.在找PHP配置文件和apache的conf文件都难找到, 我们应该大致的了解下linux的文件分布 /etc : 放置系统重 ...

  3. php递归函数,性能给力

    function arPro($data,$res=array(),$pid='0',$level='0'){ foreach ($data as $k => $v){ if($v['comme ...

  4. Python第一天-----简单登录验证

    ----------------------------------------- 编写登录接口 要求:1.输入用户名密码 2.认证成功后显示欢迎信息 3.输错三次后锁定 -------------- ...

  5. 寒冰王座(hd1248)

    寒冰王座 Problem Description 不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店 ...

  6. 无意发现vim里插入模式可以借助Alt键输入一些特殊字符

    无意发现vim里插入模式可以借助Alt键输入一些特殊字符.如: Alt+w: ÷ Alt+:: » Alt+f  :  æ Alt+ . :  ® Alt+ ? :  ¯...

  7. 【Mysql5.7数据目录和配置文件目录】

    Win7下 C:\ProgramData\MySQL\MySQL Server 5.7\ 如何查看mysql运行.访问记录等日志 1.首先确认你日志是否启用了mysql>show variabl ...

  8. codevs1166 矩阵取数游戏

    题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个 ...

  9. wikioi1450 xth的旅行

    题目描述 Description 毕业了,Xth很高兴,因为他要和他的 rabbit 去双人旅行了.他们来到了水城威尼 斯.众所周知(⊙﹏⊙b汗),这里的水路交通很发达,所以 xth 和 rabbit ...

  10. ranlib的作用 -----更新静态库的符号索引表

    摘自 http://blog.csdn.net/jubincn/article/details/6958840 更新静态库的符号索引表 本小节的内容相对简单.前边提到过,静态库文件需要使用“ar”来创 ...