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在反序列化處理也是類似的,這樣整體邏輯比較清晰。
下載源碼導入到工程中,新建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 + '\'' + '}'; } }
當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; } }
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反序列化類映射關系。
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); } }
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()); } // ... }
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