【Tool】JSONUtil

Note: For learning only, do not use for production 

package com.servlet.demo.framework.utill;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import com.servlet.demo.framework.utill.clazz.ClassUtil;

/**
 * json简单工具类
 * 支持对象>JSON ; JSON > 对象
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class JsonUtil {

    private static int convertDepth = 15;
    private static String timestampPattern = "yyyy-MM-dd HH:mm:ss";
    private static String datePattern = "yyyy-MM-dd";

    public static void setConvertDepth(int convertDepth) {
        if (convertDepth < 2) throw new IllegalArgumentException("convert depth can not less than 2.");
        JsonUtil.convertDepth = convertDepth;
    }

    public static void setTimestampPattern(String timestampPattern) {
        if (timestampPattern == null || "".equals(timestampPattern.trim())) throw new IllegalArgumentException("timestampPattern can not be blank.");
        JsonUtil.timestampPattern = timestampPattern;
    }

    public static void setDatePattern(String datePattern) {
        if (datePattern == null || "".equals(datePattern.trim())) throw new IllegalArgumentException("datePattern can not be blank.");
        JsonUtil.datePattern = datePattern;
    }

    // ===================================================================================

    public static String toJson(Object value) {
        return toJson(value, convertDepth);
    }


    public static String toJson(Object value, int depth) {
        if (value == null || (depth--) < 0) return "null";

        if (value instanceof String) return "\"" + escape((String) value) + "\"";

        if (value instanceof Double) {
            if (((Double) value).isInfinite() || ((Double) value).isNaN())
                return "null";
            else
                return value.toString();
        }
        if (value instanceof Float) {
            if (((Float) value).isInfinite() || ((Float) value).isNaN())
                return "null";
            else
                return value.toString();
        }
        if (value instanceof Number) return value.toString();
        if (value instanceof Boolean) return value.toString();
        if (value instanceof java.util.Date) {
            if (value instanceof java.sql.Timestamp) return "\"" + new SimpleDateFormat(timestampPattern).format(value) + "\"";
            if (value instanceof java.sql.Time) return "\"" + value.toString() + "\"";
            return "\"" + new SimpleDateFormat(datePattern).format(value) + "\"";
        }
        if (value instanceof Map) {
            return mapToJson((Map) value, depth);
        }
        if (value instanceof List) {
            return listToJson((List) value, depth);
        }
        String result = otherToJson(value, depth);
        if (result != null) return result;
        // 类型无法处理时当作字符串处理,否则ajax调用返回时js无法解析
        // return value.toString();
        return "\"" + escape(value.toString()) + "\"";
    }

    private static String mapToJson(Map map, int depth) {
        if (map == null) return "null";

        StringBuilder sb = new StringBuilder();
        boolean first = true;
        Iterator iter = map.entrySet().iterator();

        sb.append('{');
        while (iter.hasNext()) {
            if (first)
                first = false;
            else
                sb.append(',');

            Map.Entry entry = (Map.Entry) iter.next();
            toKeyValue(String.valueOf(entry.getKey()), entry.getValue(), sb, depth);
        }
        sb.append('}');
        return sb.toString();
    }

    private static String toKeyValue(String key, Object value, StringBuilder sb, int depth) {
        sb.append('\"');
        if (key == null)
            sb.append("null");
        else
            escape(key, sb);
        sb.append('\"').append(':');
        sb.append(toJson(value, depth));
        return sb.toString();
    }

    private static String listToJson(List list, int depth) {
        if (list == null) return "null";
        boolean first = true;
        StringBuilder sb = new StringBuilder();
        Iterator iter = list.iterator();
        sb.append('[');
        while (iter.hasNext()) {
            if (first)
                first = false;
            else
                sb.append(',');
            Object value = iter.next();
            if (value == null) {
                sb.append("null");
                continue;
            }
            sb.append(toJson(value, depth));
        }
        sb.append(']');
        return sb.toString();
    }

    /**
     * Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters
     * (U+0000 through U+001F).
     */
    private static String escape(String s) {
        if (s == null) return null;
        StringBuilder sb = new StringBuilder();
        escape(s, sb);
        return sb.toString();
    }

    private static void escape(String s, StringBuilder sb) {
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            switch (ch) {
                case '"':
                    sb.append("\\\"");
                    break;
                case '\\':
                    sb.append("\\\\");
                    break;
                case '\b':
                    sb.append("\\b");
                    break;
                case '\f':
                    sb.append("\\f");
                    break;
                case '\n':
                    sb.append("\\n");
                    break;
                case '\r':
                    sb.append("\\r");
                    break;
                case '\t':
                    sb.append("\\t");
                    break;
//                case '/':
//                    sb.append("\\/");
//                    break;
                default:
                    if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) {
                        String str = Integer.toHexString(ch);
                        sb.append("\\u");
                        for (int k = 0; k < 4 - str.length(); k++) {
                            sb.append('0');
                        }
                        sb.append(str.toUpperCase());
                    } else {
                        sb.append(ch);
                    }
            }
        }
    }



    private static String otherToJson(Object value, int depth) {
        if (value instanceof Character) {
            return "\"" + escape(value.toString()) + "\"";
        }
        if (value instanceof Object[]) {
            Object[] arr = (Object[]) value;
            List list = new ArrayList(arr.length);
            for (int i = 0; i < arr.length; i++)
                list.add(arr[i]);
            return listToJson(list, depth);
        }
        if (value instanceof Enum) {
            return "\"" + ((Enum) value).toString() + "\"";
        }
        if (value instanceof Class) {
            return "\"" + ((Class) value).getName() + "\"";
        }
        return beanToJson(value, depth);
    }

    private static String beanToJson(Object model, int depth) {
        Map map = new HashMap();
        Method[] methods = model.getClass().getMethods();
        for (Method m : methods) {
            String methodName = m.getName();
            int indexOfGet = methodName.indexOf("get");
            if (indexOfGet == 0 && methodName.length() > 3) { // Only getter
                String attrName = methodName.substring(3);
                if (!attrName.equals("Class")) { // Ignore Object.getClass()
                    Class<?>[] types = m.getParameterTypes();
                    if (types.length == 0) {
                        try {
                            Object value = m.invoke(model);
                            map.put(FormatUtil.firstCharToLowerCase(attrName), value);
                        } catch (Exception e) {
                            throw new RuntimeException(e.getMessage(), e);
                        }
                    }
                }
            } else {
                int indexOfIs = methodName.indexOf("is");
                if (indexOfIs == 0 && methodName.length() > 2) {
                    String attrName = methodName.substring(2);
                    Class<?>[] types = m.getParameterTypes();
                    if (types.length == 0) {
                        try {
                            Object value = m.invoke(model);
                            map.put(FormatUtil.firstCharToLowerCase(attrName), value);
                        } catch (Exception e) {
                            throw new RuntimeException(e.getMessage(), e);
                        }
                    }
                }
            }
        }
        return mapToJson(map, depth);
    }

    // ========================================================
    public static Object parse(String jsonStr) {
        int len = jsonStr.length();
        String sp = "|";//
        Boolean cs = Boolean.FALSE, ignore = Boolean.FALSE;
        Stack<Character> s1 = new Stack<Character>();// 符号
        Stack<Object> s2 = new Stack<Object>();// 值
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++) {
            char c = jsonStr.charAt(i);
            switch (c) {
                case '{':
                case '[':
                    s1.add(c);
                    s2.add(sp);
                    sb.setLength(0);
                    break;
                case ']':
                case '}':
                    if (s1.peek() != '"') {
                        cs = addCheck(sb, cs, s2);
                        char ls2 = s1.pop();
                        if ((c == '}' && ls2 != '{') || (c == ']' && ls2 != '[')) throw new RuntimeException("JSON 格式错误 ");
                        Object obj = null;
                        // =================
                        if (c == '}') {// map
                            Map map = new HashMap<>();
                            while (!sp.equals(s2.peek())) {
                                Object v = s2.pop();
                                if ("".equals(v) && sp.equals(s2.peek())) // 验证空对象
                                    continue;
                                Object k = s2.pop();
                                map.put(k, v);
                            }
                            obj = map;
                        }
                        if (c == ']') {// list
                            List list = new ArrayList<>();
                            while (!sp.equals(s2.peek())) {
                                list.add(s2.pop());
                            }
                            obj = list;
                        }
                        // =================
                        s2.pop();
                        s2.add(obj);
                        ignore = Boolean.TRUE;
                    } else {
                        sb.append(c);
                    }
                    break;
                case '"':
                    if (jsonStr.charAt(i - 1) != '\\') if (s1.peek() == '"') {
                        s1.pop();
                        cs = Boolean.TRUE;
                    } else
                        s1.add('"');
                    break;
                case ':':
                case ',':
                    if (s1.peek() != '"') {
                        if (ignore && c == ',') {
                            ignore = Boolean.FALSE;
                            continue;
                        }
                        cs = addCheck(sb, cs, s2);
                    } else {
                        sb.append(c);
                    }
                    break;
                default:
                    sb.append(c);
                    break;
            }
        }
        if (!s1.isEmpty()) System.out.println("JSON 格式结尾缺失");
        return s2.pop();
    }

    private static boolean addCheck(StringBuffer sb, Boolean cs, Stack<Object> s2) {
        Object val = sb.toString().trim();
        if (!cs) {
            if (FormatUtil.isNumber(val))
                val = FormatUtil.toLong(val);
            else if (FormatUtil.isDecimal(val))
                val = FormatUtil.toDouble(val);
            else if (((String) val).equalsIgnoreCase("null"))
                val = null;
            else if (((String) val).equalsIgnoreCase("")) {
                sb.setLength(0);
                return false;
            } else
                val = FormatUtil.toBoolean(val);
        }
        s2.add(val);
        sb.setLength(0);
        return false;
    }

    public static <T> Object parse(String jsonStr, Class<T> clazz) throws Exception {
        Object jsonObj = parse(jsonStr);
        return parseBean(jsonObj, clazz);
    }

    private static <T> Object parseBean(Object json, Class<T> clazz) throws Exception {
        try {
            if (json instanceof List) {
                List<T> list = new ArrayList<T>();
                for (Object obj : (List) json) {
                    if (!obj.equals("")) {
                        list.add((T) parseBean(obj, clazz));
                    }
                }
                return list;
            } else if (json instanceof Map) {
                Object obj = null;
                obj = clazz.newInstance();
                Set<Map.Entry<?, ?>> setMap = ((Map) json).entrySet();
                for (Map.Entry<?, ?> en : setMap) {
                    String key = FormatUtil.toString(en.getKey());
                    Object value = en.getValue();
                    Method m = null;
                    for (Method mt : clazz.getMethods()) {
                        if (mt.getName().equals("set" + FormatUtil.firstCharToUpperCase(key))) m = mt;
                    }
                    if (m != null) {
                        Class cla = m.getParameterTypes()[0];
                        Object args = null;
                        if (value != null) {
                            if (cla.isAssignableFrom(Map.class)) {
                                cla = (Class) ((ParameterizedType) (m.getGenericParameterTypes()[0])).getActualTypeArguments()[1];
                                Map map = new HashMap<>();
                                Set<Map.Entry<?, ?>> setMap2 = ((Map) value).entrySet();
                                for (Map.Entry<?, ?> en2 : setMap2) {
                                    map.put(parseBean(en2.getKey(), String.class), parseBean(en2.getValue(), cla));
                                }
                                args = map;
                            } else {
                                if (cla.isAssignableFrom(List.class)) cla = (Class) ((ParameterizedType) (m.getGenericParameterTypes()[0])).getActualTypeArguments()[0];
                                args = parseBean(value, cla);
                            }
                        }
                        m.invoke(obj, args);
                    }
                }
                return obj;
            } else if (json instanceof String[]) {
                String[] strs = (String[]) json;
                Object[] objs = new Object[strs.length];
                for (int i = 0; i < strs.length; i++) {
                    objs[i] = parse(strs[i], clazz);
                }
                return objs;
            } else {
                if (ClassUtil.isString(clazz)) {
                    return FormatUtil.toString(json);
                } else if (ClassUtil.isDouble(clazz)) {
                    return FormatUtil.toDouble(json);
                } else if (ClassUtil.isInt(clazz)) {
                    return FormatUtil.toInt(json);
                } else if (ClassUtil.isLong(clazz)) {
                    return FormatUtil.toLong(json);
                } else if (ClassUtil.isDecimal(clazz)) {
                    return FormatUtil.toDecimal(json);
                } else if (ClassUtil.isBool(clazz)) {
                    return FormatUtil.toBoolean(json);
                } else {
                    throw new Exception("未知文件类型转换:value=" + json + ",type=" + clazz);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325351736&siteId=291194637
Recommended