欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java实现简单的Json解析器<二>

程序员文章站 2022-07-13 12:06:55
...

源代码见:https://github.com/Slive/org.slive.simpleJson


Json String解析为Java对象

相对于“将Java 对象转换Json String”更为复杂一些,这里分两步走:

第一步,将Json String 转换为一个Java JsonObject类,JsonObject类似一个树结构,用于存储Json信息。

第二步,将Java JsonObject类解析为Java对象实例。

Json String 转换为一个Java JsonObject类:

JsonObject实际就是对应Json结构,val->Json Valueval只能是Java StringJava MapJava Lis,其中Map->Json ObjectList->Json Array),key->Json key三种结构,由于是嵌套的,所以还定义了一个parent,具体见Json#JsonObject.java:

static class JsonObject {

        private JsonObject parent;

        private String key;

        private Object val;

        public JsonObject(JsonObject parent, String key, Map<String, Object> val) {
            this.parent = parent;
            this.key = key;
            this.val = val;
            relateParent(parent, key, val);
        }

        public JsonObject(JsonObject parent, String key, List<Object> val) {
            this.parent = parent;
            this.key = key;
            this.val = val;
            relateParent(parent, key, val);
        }

        /**
         * 与父类建立关系
         */
        @SuppressWarnings("unchecked")
        private void relateParent(JsonObject parent, String key, Object val) {
            if (parent != null && val != null) {
                Object pVal = parent.getVal();
                if (pVal != null) {
                    if (pVal instanceof Map && CommonUtils.isNotEmpty(key)) {
                        ((Map<String, Object>) pVal).put(key, val);
                    } else if (pVal instanceof List) {
                        ((List<Object>) pVal).add(val);
                    }
                }
            }
        }

        public JsonObject getParent() {
            if (parent == null) {
                parent = this;
            }
            return parent;
        }

        public String getKey() {
            return key;
        }

        public Object getVal() {
            return val;
        }

        @Override
        public String toString() {
            return val != null ? val.toString() : null;
        }

    }

Json String解析为JsonObject流程图:

Java实现简单的Json解析器<二>

最终解析出来的是一个JsonObject对象实例,该对象实例中又包含了子JsonObject,就像一个树结构,具体代码如下:

private static JsonObject toJsonObject(String jsonStr) {
        if (CommonUtils.isEmpty(jsonStr)) {
            return null;
        }
        JsonObject jb = null;
        StringBuilder sbd = new StringBuilder();
        char[] jcs = jsonStr.toCharArray();
        int jLen = jcs.length;
        String key = null;
        String val = null;
        Object jVal = null;
        char jc;
        for (int index = 0; index < jLen; index++) {
            jc = jcs[index];
            if (jc == '{') {
                // 初始化为Map
                jb = new JsonObject(jb, key, new HashMap<String, Object>());
            } else if (jc == '[') {
                // 初始化为List
                jb = new JsonObject(jb, key, new ArrayList<Object>());
            } else if (jc == ':') {
                // 获取key
                key = getAndCleanSbdStr(sbd);
            } else if (jc == ',' || jc == '}' || jc == ']') {
                // 获取val
                val = getAndCleanSbdStr(sbd);
                // 处理值
                if (jb != null && CommonUtils.isNotEmpty(val)) {
                    jVal = jb.getVal();
                    if (jVal instanceof Map && CommonUtils.isNotEmpty(key)) {
                        ((Map<String, Object>) jVal).put(key, val);
                    } else if (jVal instanceof List) {
                        ((List<Object>) jVal).add(val);
                    }
                }

                // 当前对象处理介绍,回退到上一个对象
                if (jc == '}' || jc == ']') {
                    jb = jb.getParent();
                    key = jb.getKey();
                }
            } else {
                sbd.append(jc);
            }
        }
        return jb;
}

Java JsonObject类解析为Java对象实例

这里会有两个参数,一个是Java JsonObject实例值,一个是目标Java对象class,转换后的结果是目标Java对象实例。如《Java实现一个简单的Json解析器(一)》提到的本文的Java对象类型分类,分别对目标Java对象的类型进行判断,根据不同类型,分别做不同的类型解析处理,解析流程如下:

Java实现简单的Json解析器<二>

有几个地方需要重点说明一下:

1、整个解析过程是嵌套执行,目标Java对象的类型和JsonObject对象的类型能对应上才能解析,否则可能被丢弃,对应关系大体如下:

(1) 目标Java对象为简单类型,则JsonObject对象的值可以为任意类型,但解析是强制转换为String再进行解析。

(2) 目标Java对象为复合或者Map类型,则JsonObject对象的值只能为Map类型。

(3) 目标Java对象为集合或者数组类型,则JsonObject对象的值只能为集合类型。

2、对于目标Java对象为非简单类型时,需要判断出pojo类中的字段,或者Map,数组,集合中定义的值对应哪个Java类(比如byte[String],则定义的值为String.class类,又比如Map<String,TestDto>,则定义的值为TestDto.class类,若无法确定,则取默认的JavaObject.class),以便作为新的目标Java对象进行嵌套解析,最终最底层都是调用简单类型进行处理,具体代码见如下:

private static Class<?> getComponentType(Type gType) {
        CommonUtils.debugLog("type is " + gType);
        if (gType instanceof Class) {
            Class<?> clazz = (Class<?>) gType;
            if (TypeUtils.isArray(clazz)) {
                return clazz.getComponentType();
            }
        }
        if (gType != null) {
            if (gType instanceof ParameterizedType) {
                Type[] ctgs = ((ParameterizedType) gType).getActualTypeArguments();
                if (ctgs.length > 0) {
                    // collection,map等,只取最后一个参数
                    return (Class<?>) ctgs[ctgs.length - 1];
                }
            } else if (gType instanceof WildcardType) {
                return (Class<?>) ((WildcardType) gType).getUpperBounds()[0];
            } else if (gType instanceof GenericArrayType) {
                return (Class<?>) ((GenericArrayType) gType).getGenericComponentType();
            } else if (gType instanceof TypeVariable) {
                return (Class<?>) ((TypeVariable) gType).getBounds()[0];
            }
        }
        return Object.class;
    }

1、对于目标Java对象中有些字段使用接口进行定义,若无法找到具体的实现类时,则通过Java代理实现settergetter方法,代码实现如下:

static class JsonInvocationHandler implements InvocationHandler {

        private Map srcVals = null;

        private Map<String, Object> vals = new HashMap<String, Object>();

        public JsonInvocationHandler(Map srcVals) {
            this.srcVals = srcVals;
        }

        @Override
        public int hashCode() {
            int code = 1;
            for (Object obj : vals.values()) {
                if (obj != null) {
                    code = code * 31 + obj.hashCode();
                }
            }
            return code;
        }

        @Override
        public Object invoke(Object ins, Method m, Object[] valObjs) throws Throwable {
            // 重点代理实现getter和setter方法
            try {
                String mName = m.getName();
                Type[] pts = m.getGenericParameterTypes();
                Class<?> retType = m.getReturnType();
                if (pts.length == 1 && retType.equals(void.class)) {
                    if (mName.startsWith("set")) {
                        String fieldName = MethodUtils.getFieldName(m, "set");
                        vals.put(fieldName, valObjs[0]);
                    }
                } else if (pts.length == 0 && !retType.equals(void.class)) {
                    if (mName.startsWith("get")) {
                        String fieldName = MethodUtils.getFieldName(m, "get");
                        if (fieldName != null) {
                            if (!vals.containsKey(fieldName)) {
                                return convertVal(pts, retType, fieldName);
                            } else {
                                return vals.get(fieldName);
                            }
                        }
                    } else if (mName.startsWith("is")) {
                        String fieldName = MethodUtils.getFieldName(m, "is");
                        if (fieldName != null) {
                            if (!vals.containsKey(fieldName)) {
                                return convertVal(pts, retType, fieldName);
                            } else {
                                return vals.get(fieldName);
                            }
                        }
                    } else if (mName.startsWith("toString")) {
                        Set<String> keySet = srcVals.keySet();
                        for (String fileName : keySet) {
                            if (!vals.containsKey(fileName)) {
                                Object srcVal = srcVals.get(fileName);
                                if (srcVal != null) {
                                    Method getM = null;
                                    String upperField = fileName.substring(0, 1).toUpperCase() + fileName.substring(1);
                                    try {
                                        getM = srcVal.getClass().getMethod("get" + upperField, null);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        try {
                                            getM = srcVal.getClass().getMethod("is" + upperField, null);
                                        } catch (Exception e2) {
                                            e2.printStackTrace();
                                        }
                                    }
                                    if (getM != null) {
                                        convertVal(null, getM.getReturnType(), fileName);
                                    }
                                }
                            }
                        }
                        return vals.toString();
                    } else if (mName.startsWith("hashCode")) {
                        return this.hashCode();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }

        private Object convertVal(Type[] pts, Class<?> retType, String fieldName) {
            // 值获取不到时,初始化转换
            Object retSrcVal = srcVals.get(fieldName);
            if (retSrcVal != null) {
                // 做值转换
                Class<?> cType = getComponentType((pts != null && pts.length > 0) ? pts[0] : retType);
                Object retVal = parseObjectInner(retType, retSrcVal, cType);
                if (retVal != null) {
                    vals.put(fieldName, retVal);
                }
                return retVal;
            }
            return null;
        }
    }

可优化地方:

1、日期(格式)处理

2、数值的处理,如科学计数法转换等

3、字符串编码处理,避免出现解析或者转换的乱码

4、格式化输出处理

5、性能和容错处理

 

总结:

1、理解Json数据结构基础上,通过与Java语言特性进行对应,实现Json解析器功能

2、划分类型,针对不同类型进行不同的处理,类型最终处理都归结为简单类型的处理

3、针对复合类型处理,需化繁为简进行处理

4、针对集合或者Map类型处理,首先要能够提取集合中对象的类型或者值,然后进行循环处理

5、理解代理实现类

 

参考:

Json介绍:http://www.json.org/

阿里巴巴Fastjsonhttps://fastjson.codeplex.com/





相关标签: Java Json