你的位置:首页 > Java教程

[Java教程]Tomjson


  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在反序列化处理也是类似的,这样整体逻辑比较清晰。

json.png

 

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.java,test是一些测试类。
  • 精悍:在小型类的序列化话速度上还是很快的 :) 。

2.2 Tomjson序列化思想

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

// ObjectSerializer - Object序列化类@Overridepublic 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