pppploi8's Blog

欢迎来到pppploi8的个人博客!

[Java]简单的JSON解析实现

话说好久没更新这个博客了

都快忘记还有博客这件事了….

因为之前在造一个简单的HTTP框架的轮子,里面用了JSON…当时随便拉了个FastJSON的库就用了,然而…嗯,毫无疑问,轮子还是要自己造才好玩,虽然不会在生产环境用,但是写和不写多少还是有些差距的

于是今天就造了这个简单的JSON库轮子,实现了FastJSON里最常用的toJSON和fromJSON功能,支持Map List Array BeanObject 的JSON文本转换,JSON文本解析的话只实现了到Map和List的解析…BeanObject懒得写了,等以后轮子的坑造完了完善后再一起丢到Coding玩好了

总之简单的放一下这个毫无效率的MyJSON代码,为了实现简单各种递归应该不复杂,至于兼容性…不知道,没测试多少测试用例,如果有BUG欢迎评论反馈(循环引用会导致生成json文本死循环,对此并不打算修复…嗯,说到底JSON里我怎么才能表示的出循环引用啊

对了,写这个的时候完全没有参考JSON规范….全靠自己对JSON的理解强行撸出来的,如果有不符合规范的地方欢迎指正QwQ

从对象生成JSON(所有的包引用就不贴了)

/**
 * 根据对象封装到JSON文本,支持Map,List和Bean对象,如果键是一个对象,那么需要自行重写toString
 * @param object
 * @return
 */
public static String toJSON(Object object){
    StringBuffer jsonString = new StringBuffer();
    if (object instanceof Map){
        getMapObjectText(jsonString,object);
    }else if(object instanceof List || object.getClass().isArray()){
        getListObjectText(jsonString,object);
    }else{
        getBeanObjectText(jsonString,object);
    }
    return jsonString.toString();
}
//从Object中解析并生成JSON字符串,如果无法作为Java Bean解析,则直接toString输出文本
private static void getBeanObjectText(StringBuffer json,Object object) {
    int i = 0;
    try{
        Class c = object.getClass();
        Field[] fields = c.getDeclaredFields();
        for(Field field : fields){
            PropertyDescriptor pd = new PropertyDescriptor(field.getName(), c);
            Method getMethod = pd.getReadMethod();
            Object value = getMethod.invoke(object);
            if (i++ == 0)
                json.append("{");
            else
                json.append(",");
            json.append("\"").append(field.getName()).append("\":");
            getValueText(json, value);
        }
    }catch(Exception e){}
    if (i != 0)
        json.append("}");
    else
        json.append("\"").append(object.toString()).append("\"");
}
//从Map中解析并生产JSON字符串
private static void getMapObjectText(StringBuffer json,Object object){
    Map<Object,Object> map = (Map)object;
    json.append("{");
    int i = 0;
    for(Entry entry : map.entrySet()){
        if (entry.getKey() != null){
            if (i++ != 0){
                json.append(",");
            }
            json.append("\"").append(entry.getKey().toString()).append("\":");
            getValueText(json, entry.getValue());
        }
    }
    json.append("}");
}
//从List或者Arrays中解析并生成JSON字符串
private static void getListObjectText(StringBuffer json,Object object){
    json.append("[");
    List list = null;
    if(object.getClass().isArray()){
        list = Arrays.asList((Object[])object);
    }
    if (list == null)
        list = (List)object;
    int i = 0;
    for(Object value : list){
        if (i++ != 0)
            json.append(",");
        getValueText(json,  value);
    }
    json.append("]");
}
//获取value的值并写入json字符串中
private static void getValueText(StringBuffer json,Object value){
    if (value == null){
        json.append("null");
        return;
    }
    if (value instanceof String)//基本数据类型处理
        json.append("\"").append(encoderJsonText(value.toString())).append("\"");
    else if(value instanceof Integer)
        json.append(((Integer) value).intValue());
    else if(value instanceof Boolean)
        json.append(((Boolean) value).booleanValue());
    else if(value instanceof Character)
        json.append("\"").append(value.toString()).append("\"");
    else if(value instanceof Long)
        json.append(((Long) value).longValue());
    else if(value instanceof Double)
        json.append(((Double) value).doubleValue());
    else if(value instanceof Float)
        json.append(((Float) value).floatValue());
    else if(value instanceof Map)//Map List Arrays Bean递归处理
        getMapObjectText(json,value);
    else if(value instanceof List || value.getClass().isArray())
        getListObjectText(json,value);
    else
        getBeanObjectText(json, value);
}
//对JSON中的文字进行编码转换,主要是"换行等符号的转义
private static String encoderJsonText(String s){
    s = s.replace("\"", "\\\"");
    s = s.replace("\\", "\\\\");
    s = s.replace("\n", "\\\n");
    return s;
}

使用方法(Bean对象请自行脑补)

TestBean bean = new TestBean();
bean.setBean1("Stri\"ngTe[]}xt");
bean.setBeanBool(true);
bean.setBeanFloat((float)3.14);
bean.setBeanInt(233);
Map<String,Object> map = new HashMap<>();
map.put("test", "a");
map.put("test2", 0);
map.put("test3", new Object());
Map<String,Object> map2 = new HashMap<>();
map2.put("map2", "qwq");
Object[] array = new Object[]{"1","2",map2};
bean.setBeanMap(map);
bean.setBeanList(Arrays.asList(array));
System.out.println(MyJSON.toJSON(bean));

接下来上JSON解析代码,思路和上面一样,全靠递归简化

private final static char[] BLANKLIST = new char[]{' ','\t','\r','\n'};//空白字符
private final static char[] LISTENDS = new char[]{',',']'};//LIST结束字符
private final static char[] MAPENDS = new char[]{',','}'};//MAP结束字符
private final static char[] COLONCHAR = new char[]{':'};//冒号CHAR
private final static char[] QUOTESCHAR = new char[]{'"'};//引号CHAR

/**
 * 解析JSON并返回解析结果,如果是键值对则封装成Map,如果是有序集合则封装成List
 * @param json
 * @return
 */
public static Object fromJSON(String json){
    json = json.trim();
    if (json.startsWith("{"))
        return getMapObjectFromJson(json, new int[]{1});
    else if (json.startsWith("["))
        return getListObjectFromJson(json, new int[]{1});
    else
        throw new IllegalArgumentException("开头不是{或者[");
}
//根据JSON文本封装成Map,pos为当前处理位置
private static Map getMapObjectFromJson(String json,int[] pos){
    Map<String,Object> resultMap = new HashMap<>();
    while(pos[0] < json.length()){
        //跳到第一个"
        jumpCharByChars(json, pos, QUOTESCHAR);
        //取到下一个"为止是key
        String key = getCharsByEnds(json, pos, QUOTESCHAR);
        pos[0]++;//跳过"符号
        //跳到中间分割字符:
        jumpCharByChars(json, pos, COLONCHAR);
        //跳到下一个非空值为止
        jumpCharByChars(json,pos,null);
        pos[0]--;//调回非空值第一个数据
        char c = json.charAt(pos[0]);
        if (c == '{'){//是一个嵌套Map
            pos[0]++;//跳过{符号
            resultMap.put(key, getMapObjectFromJson(json, pos));
        }else if(c == '['){//是一个嵌套List
            pos[0]++;//跳过[符号
            resultMap.put(key, getListObjectFromJson(json, pos));
        }else if(c == '"'){//文本值处理
            pos[0]++;
            String value = getCharsByEnds(json, pos, QUOTESCHAR);
            pos[0]++;
            resultMap.put(key, decoderJsonText(value));
        }else{//其他格式处理
            String value = getCharsByEnds(json, pos, MAPENDS);
            resultMap.put(key, getTextValue(value));
        }
        if (isEnds(json,pos))//是否结束
            return resultMap;
    }
    throw new IllegalArgumentException("异常的结尾,请检查JSON字符串是否完整");
}
//根据JSON中的文本值获取对应实例(主要是int bool null三种特殊值)
private static Object getTextValue(String s){
    s = s.trim();
    if ("true".equals(s))
        return true;
    if ("false".equals(s))
        return false;
    if ("null".equals(s))
        return null;
    if (s.indexOf(".")==-1){
        try{
            return Integer.parseInt(s);
        }catch(NumberFormatException e){
            return Long.parseLong(s);
        }
    }else{
        try{
            return Float.parseFloat(s);
        }catch(NumberFormatException e){
            return Double.parseDouble(s);
        }
    }
}
//根据JSON文本封装成List,pos为当前处理位置
private static List getListObjectFromJson(String json,int[] pos){
    List<Object> resultList = new ArrayList<>();
    while(pos[0] < json.length()){
        jumpCharByChars(json, pos, null);
        pos[0]--;
        char c = json.charAt(pos[0]);
        if (c == '{'){
            pos[0]++;
            resultList.add(getMapObjectFromJson(json, pos));
        }else if (c == '['){
            pos[0]++;
            resultList.add(getListObjectFromJson(json, pos));
        }else if (c == '"'){
            pos[0]++;
            String value = getCharsByEnds(json, pos, QUOTESCHAR);
            pos[0]++;
            resultList.add(decoderJsonText(value));
        }else{
            String value = getCharsByEnds(json, pos, LISTENDS);
            resultList.add(getTextValue(value));
        }
        if (isEnds(json,pos))
            return resultList;
    } 
    throw new IllegalArgumentException("异常的结尾,请检查JSON字符串是否完整");
}
//判断是否结束
private static boolean isEnds(String json,int[] pos){
    int i = pos[0];
    while(i < json.length()){
        char c = json.charAt(i++);
        if (!isBlank(c)){
            if (c == '}' || c == ']'){
                pos[0] = i;
                return true;
            }else if (c == ','){
                pos[0] = i;
                return false;
            }else
                throw new IllegalArgumentException("未知的字符[" + c + "],在"+i+"位置");
        }
    }
    throw new IllegalArgumentException("异常的结尾,请检查JSON字符串是否完整");
}
//根据chars跳过一定数量的位置,如果遇到非空且不在chars中的字符则抛出异常
private static void jumpCharByChars(String json,int[] pos,char[] chars){
    while(pos[0] < json.length()){
        char c = json.charAt(pos[0]);
        if (!isBlank(c)){
            if (charInChars(c,chars))
                break;
            throw new IllegalArgumentException("未知的字符[" + c + "],在"+pos[0]+"位置");
        }
        pos[0]++;
    }
    pos[0]++;
    if (pos[0] > json.length())
        throw new IllegalArgumentException("异常的结尾,请检查JSON字符串是否完整");
}
//根据ends来获取ends前的所有内容文本,转义字符完整输出不作处理
private static String getCharsByEnds(String json,int[] pos,char[] ends){
    CharArrayWriter out = new CharArrayWriter(1);
    while(pos[0] < json.length()){
        char c = json.charAt(pos[0]);
        if (c == '\\'){
            out.write(c);
            out.write(json.charAt(++pos[0]));
        }else if(charInChars(c,ends)){
            break;
        }else{
            out.write(c);
        }
        pos[0]++;
    }
    if (pos[0]+1 > json.length())
        throw new IllegalArgumentException("异常的结尾,请检查JSON字符串是否完整");
    String result = null;
    result = new String(out.toCharArray());
    out.close();
    return result;
}
//检测字符是不是在字符数组中
private static boolean charInChars(char c,char[] chars){
    if (chars == null)
        return true;
    for(char cc : chars)
        if (cc == c)
            return true;
    return false;
}
//检测字符是不是空白
private static boolean isBlank(char s){
    for(char c : BLANKLIST)
        if (s == c)
            return true;
    return false;
}
//解码JSON文本,主要是对转义字符的解释
private static String decoderJsonText(String s){
    s = s.replace("\\\"", "\"");
    s = s.replace("\\\\", "\\");
    s = s.replace("\\\n", "\n");
    return s;
}

使用方法

public void test(){
    Map m = (Map)MyJSON.fromJSON("{\"test\":[{\"test\":2},{\"test2\":[1,2,3]}]}");
    System.out.print(m);
}