程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Tomjson,json

Tomjson,json

編輯:JAVA綜合教程

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在反序列化處理也是類似的,這樣整體邏輯比較清晰。

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序列化類
@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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved