Simplify-Core --Json解析(Json parser)

来源:互联网 发布:android程序员 编辑:程序博客网 时间:2024/06/06 00:05

在上一篇文章中,我们看到了一个java对象是怎么转换成json规范的字符串,这一次是反过来,从json字符串解析json内容,并且合成java bean,先上我的Simplify项目地址项目,欢迎路过的大牛对项目提出建议。

项目地址:https://github.com/lovejj1994/Simplify-Core

还是再贴一下json框架的架构图,因为不管是解析还是生成,都跟这个架构有关系。
这里写图片描述

先对json字符串进行解析

要转换成json对象,你首先需要对json字符串进行解析,解析的大致原理在于先给一个栈,然后对不同的字符做不同的处理,比如你碰到一个大括号({),你应该知道json需要一个map对象去装key,value值,当你碰到一个中括号([),你应该知道需要一个数组对象去装数组等等,因为字符串从前往后解析,所以需要栈结构,利用入栈,出栈来完成解析逻辑,打个比方,当你碰到大括号,你需要先把一个JsonObject(实质是map)压入栈,然后继续解析后面的字符串,这个字符串必定是key值,并且将这个字符串压入栈,后面一会碰到冒号(:),说明后面是value,你需要读取这个value值并压入栈,最后,你碰到 后大括号(}),说明你需要把前面的key,value,以及JsonObject依次弹出栈,并把key,value值放入JsonObject中,然后把JsonObject重新压入栈。如果json字符串符合规范的话,最后你的栈应该只剩下一个JsonObject,这时候,你的解析工作就算完成了,当然,实际情况不止那么简单,所以会用到递归逐层解析。

解析代码逻辑大致如下:

public JsonObject parseObject(String text) {    Stack<Object> stacks = new Stack<>();    String status = Const.BEGIN;    char[] chars = text.toCharArray();    if (chars.length > 0) {        if (!(Const.PRE_BRACE_CHAR == chars[0])) {            throw new RuntimeException("The structure of jsonString is wrong ");        }        for (int i = 0; i < chars.length; i++) {            switch (chars[i]) {                //碰到 {                case Const.PRE_BRACE_CHAR: {                    status = Const.KEY;                    JsonObject jo = new JsonObject();                    stacks.push(jo);                    break;                }                //碰到 }                case Const.POST_BRACE_CHAR: {                    groupJsonObject(stacks, status);                    break;                }                //碰到 "                case Const.SINGLE_QUOTES_CHAR: {                    if (Const.KEY.equals(status)) {                        pushNewString(stacks);                    } else if (Const.VALUE.equals(status)) {                        pushNewString(stacks);                        status = Const.READINGSTRING;                    }                    break;                }                //碰到 :                case Const.COLON_CHAR: {                    if (!status.equals(Const.READINGSTRING)) {                        status = Const.VALUE;                    } else {                        readValue(stacks, chars, i);                    }                    break;                }                //碰到 ,                case Const.COMMA_CHAR: {                    groupJsonObject(stacks, status);                    if (JsonArray.class == stacks.peek().getClass()) {                        if (i + 1 < chars.length) {                            char c = chars[i + 1];                            if (c != Const.SINGLE_QUOTES_CHAR) {                                status = Const.VALUE;                            } else {                                status = Const.KEY;                            }                        } else {                            throw new RuntimeException("The structure of jsonString is wrong ");                        }                    } else {                        status = Const.KEY;                    }                    break;                }                //碰到 [                case Const.PRE_BRACKET_CHAR: {                    JsonArray<Object> jsonArray = new JsonArray<>();                    stacks.push(jsonArray);                    break;                }                //碰到 ]                case Const.POST_BRACKET_CHAR: {                    if (JsonObject.class == stacks.peek().getClass()) {                        JsonObject jsonObject = (JsonObject) stacks.pop();                        if (JsonArray.class == stacks.peek().getClass()) {                            JsonArray<Object> jsonArray = (JsonArray<Object>) stacks.pop();                            jsonArray.add(jsonObject);                            stacks.push(jsonArray);                        }                    } else if (StringBuffer.class == stacks.peek().getClass()) {                        StringBuffer value = (StringBuffer) stacks.pop();                        String s = value.toString();                        if (JsonArray.class == stacks.peek().getClass()) {                            JsonArray<Object> jsonArray = (JsonArray<Object>) stacks.pop();                            addValueForJsonArray(jsonArray, s);                            stacks.push(jsonArray);                        }                    }                    break;                }                default: {                    if (Const.VALUE.equals(status)) {                        pushNewString(stacks);                    }                    if (Const.READINGSTRING.equals(status)) {                    } else {                        status = Const.READING;                    }                    readValue(stacks, chars, i);                    break;                }            }        }    }    if (stacks.size() != 1) {        throw new RuntimeException("The structure of jsonString is wrong ");    } else {        return (JsonObject) stacks.pop();    }}

总的来说就是碰到不同的字符 需要做不同的处理,最后的jsonObject对象便是从String转换成java对象的第一步,当然,我们还需要把jsonObject 对象转换成我们实际需要的类,这里又用到了codec处理器。

codec不仅负责生成,也负责解析

我们知道,在Ijson接口中,除了writeJsonString用于生成json,还有一个parse方法,用于将解析出来的jsonObject转换成我们实际业务场景需要的类,而不仅仅是个简单的map结构类型。

Object parse(Object o, Method m);

这里主要用到的还是反射机制,在parse方法中,第一个object是不准确的数据类型,是需要我们待处理的字段,第二个参数method是我们实际业务场景中 该字段的set方法,我们通过反射可以知道它实际的数据类型,并作针对的处理,如果该字段是array,我们还需要知道它的泛型。

以Number数据类型为例,部分代码如下:

@Overridepublic Object parse(Object o, Method m) {    Class<?> parameterTypes = getParameterTypes(m);    //如果参数是map,我们需要知道它泛型,就是真正的字段类型    if (Map.class.isAssignableFrom(parameterTypes)) {        Type actualTypeArguments = getActualTypeArguments(m);        return numberParse(o, (Class) actualTypeArguments);    }    return numberParse(o, parameterTypes);}//具体的Number解析逻辑,每一种数字类型都需要兼顾到private Object numberParse(Object o, Class parameterTypes) {    if (parameterTypes == int.class || parameterTypes == Integer.class) {        if (o instanceof Integer) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).intValue();        } else if (o instanceof BigInteger) {            return ((BigInteger) o).intValue();        }        return o;    }    if (parameterTypes == long.class || parameterTypes == Long.class) {        if (o instanceof Long) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).longValue();        } else if (o instanceof Integer) {            return ((Integer) o).longValue();        }    }    if (parameterTypes == short.class || parameterTypes == Short.class) {        if (o instanceof Short) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).shortValue();        } else if (o instanceof Integer) {            return ((Integer) o).shortValue();        }    }    if (parameterTypes == double.class || parameterTypes == Double.class) {        if (o instanceof Double) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).doubleValue();        } else if (o instanceof Integer) {            return ((Integer) o).doubleValue();        }    }    if (parameterTypes == float.class || parameterTypes == Float.class) {        if (o instanceof Float) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).floatValue();        } else if (o instanceof Integer) {            return ((Integer) o).floatValue();        }    }    if (parameterTypes == byte.class || parameterTypes == Byte.class) {        if (o instanceof Byte) {            return o;        } else if (o instanceof BigDecimal) {            return ((BigDecimal) o).byteValue();        } else if (o instanceof Integer) {            return ((Integer) o).byteValue();        }    }    throw new JsonException("unsupport type " + parameterTypes);}

当拿到真正的值,我们就可以通过反射调用set方法进行赋值,也就完成了整个json解析的流程。

整个过程讲的比较粗糙,可以参照源码和测试用例来看,项目还在不断的完善中,而且也不止json这一块内容,Simplify就是希望能减少显式的java代码,提高编程效率,精力有限,有问题随时指出,谢谢~!