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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lovejj1994/article/details/75213028

在上一篇文章中,我们看到了一个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数据类型为例,部分代码如下:

@Override
public 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代码,提高编程效率,精力有限,有问题随时指出,谢谢~!

猜你喜欢

转载自blog.csdn.net/lovejj1994/article/details/75213028