您的位置:首页 > Web前端 > JavaScript

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

2017-07-16 23:17 190 查看
在上一篇文章中,我们看到了一个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代码,提高编程效率,精力有限,有问题随时指出,谢谢~!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息