将Json String解析为Java对象

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

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

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

将Json String 转换为一个Java JsonObject类:

JsonObject实际就是对应Json结构,val->Json Value(val只能是Java String,Java Map,Java Lis,其中Map->Json Object,List->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解析map java json解析器实现_java json解析map


最终解析出来的是一个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解析map java json解析器实现_List_02


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

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类,若无法确定,则取默认的Java的Object.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代理实现setter和getter方法,代码实现如下:

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、理解代理实现类