基于Antlr实现基本json解析器

整天写代码都直接用fastjson,有一天我想,我自己能不能实现一套自己的fastjson

说干就干,首先拿到json的语法文件,基于它我们就可以生成antlr的一些基础类代码。

不清楚的请参考之前的博文。

// Derived from http://json.org

grammar JSON;
@header{package com.example.json;}

json:   object
    |   array
    ;

object
    :   '{' pair (',' pair)* '}' # AnObject
    |   '{' '}'                  # EmptyObject
    ;
pair:   STRING ':' value ;

array
    :   '[' value (',' value)* ']' # ArrayOfValues
    |   '[' ']'                    # EmptyArray
    ;

value
    :   STRING  # String
    |   NUMBER  # Atom
    |   object  # ObjectValue
    |   array   # ArrayValue
    |   'true'  # Atom
    |   'false' # Atom
    |   'null'  # Atom
    ;

STRING :  '"' (ESC | ~["\\])* '"' ;

fragment ESC :   '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;

NUMBER
    :   '-'? INT '.' [0-9]+ EXP? // 1.35, 1.35E-9, 0.3, -4.5
    |   '-'? INT EXP             // 1e10 -3e4
    |   '-'? INT                 // -3, 45
    ;
fragment INT :   '0' | [1-9] [0-9]* ; // no leading zeros
fragment EXP :   [Ee] [+\-]? INT ; // \- since - means "range" inside [...]

WS  :   [ \t\n\r]+ -> skip ;

拿到类文件之后,我们继承抽象visit方法,实现自己的访问者

public class JSONObjectVisitor extends JSONBaseVisitor<Object> {
    @Override
    public Object visitJson(JSONParser.JsonContext ctx) {
        return super.visitJson(ctx);
    }

    @Override
    public Object visitAnObject(JSONParser.AnObjectContext ctx) {
        HashMap<String, Object> map = new HashMap<>();
        for (JSONParser.PairContext pairContext : ctx.pair()) {
            map.putAll((Map<? extends String, ?>) visitPair(pairContext));
        }
        return map;
    }

    @Override
    public Object visitEmptyObject(JSONParser.EmptyObjectContext ctx) {
        return new HashMap<String, Object>();
    }

    @Override
    public Object visitPair(JSONParser.PairContext ctx) {
        Map<String, Object> map = new HashMap<>();
        TerminalNode string = ctx.STRING();
        String key =stripQuotes( string.getText());
        //todo
        JSONParser.ValueContext value = ctx.value();
        if (value instanceof JSONParser.StringContext) {
            map.put(key, visitString((JSONParser.StringContext) value));
        } else if (value instanceof JSONParser.ObjectValueContext) {
            map.put(key, visitObjectValue((JSONParser.ObjectValueContext) value));
        } else if (value instanceof JSONParser.ArrayValueContext) {
            map.put(key, visitArrayValue((JSONParser.ArrayValueContext) value));
        } else {
            map.put(key, visitAtom((JSONParser.AtomContext) value));
        }
        return map;
    }

    @Override
    public Object visitArrayOfValues(JSONParser.ArrayOfValuesContext ctx) {
        ArrayList<Object> list = new ArrayList<>();
        List<JSONParser.ValueContext> values = ctx.value();
        for (JSONParser.ValueContext value : values) {
            if (value instanceof JSONParser.StringContext) {
                list.add(visitString((JSONParser.StringContext) value));
            } else if (value instanceof JSONParser.ObjectValueContext) {
                list.add(visitObjectValue((JSONParser.ObjectValueContext) value));
            } else if (value instanceof JSONParser.ArrayValueContext) {
                list.add(visitArrayValue((JSONParser.ArrayValueContext) value));
            } else {
                list.add(visitAtom((JSONParser.AtomContext) value));
            }
        }
        return list;
    }

    @Override
    public Object visitEmptyArray(JSONParser.EmptyArrayContext ctx) {
        return new ArrayList<>();
    }

    @Override
    public Object visitString(JSONParser.StringContext ctx) {
        return stripQuotes( ctx.getText());
    }

    @Override
    public Object visitAtom(JSONParser.AtomContext ctx) {
        String text = ctx.getText();
        switch (text) {
            case "null":
                return null;
            case "true":
                return true;
            case "false":
                return false;
            default:
                return text;
        }
    }

    @Override
    public Object visitObjectValue(JSONParser.ObjectValueContext ctx) {
        JSONParser.ObjectContext object = ctx.object();
        if (object instanceof JSONParser.AnObjectContext) {
            return visitAnObject((JSONParser.AnObjectContext) object);
        } else {
            return visitEmptyObject((JSONParser.EmptyObjectContext) object);
        }
    }

    @Override
    public Object visitArrayValue(JSONParser.ArrayValueContext ctx) {
        JSONParser.ArrayContext array = ctx.array();
        if (array instanceof JSONParser.ArrayOfValuesContext) {
            return visitArrayOfValues((JSONParser.ArrayOfValuesContext) array);
        } else {
            return visitEmptyArray((JSONParser.EmptyArrayContext) array);
        }
    }


    //剥离json双引号
    public static String stripQuotes(String s) {
        if (s == null || s.charAt(0) != '"') return s;
        return s.substring(1, s.length() - 1);
    }
}

经过访问者访问完一遍字符串后,就可以生成一颗抽象语法树

我们的json解析就基于这颗树来实现。

public class JSON {
    /**
     * 从一个json字符串,根据指定类解析出对象
     * @param text
     * @param clazz
     * @return
     * @param <T>
     */
    public static <T> T parseObject(String text, Class<T> clazz) {
        Object parse = preParse(text);
        return parseObject((Map<String, Object>) parse, clazz);
    }


    public static <T> T parseObject(Map<String, Object> map, Class<T> clazz) {
        T t = null;
        try {
            t = clazz.getDeclaredConstructor().newInstance();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                String name = field.getName();
                field.setAccessible(true);
                Object o = map.get(name);
                if (o instanceof Map) {
                    Class<?> type = field.getType();
                    Object parsedObj = parseObject((Map) o, type);
                    field.set(t, parsedObj);
                } else if (o instanceof List) {
                    Type genericType = field.getGenericType();
                    if (genericType instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) genericType;
                        //实际的泛型参数
                        Type actualType = parameterizedType.getActualTypeArguments()[0];
                        Class<?> aClass = Class.forName(actualType.getTypeName());
                        List listObj = (List) o;
                        Object collect = listObj.stream().map(lo -> {
                            if (lo instanceof Map) {
                                return parseObject((Map) lo, aClass);
                            } else {
                                return lo;
                            }
                        }).collect(Collectors.toList());
                        field.set(t, collect);
                    }
                } else if (field.getType() == Integer.class) {
                    field.set(t, Integer.parseInt(o.toString()));
                } else if (field.getType() == Double.class) {
                    field.set(t, Double.parseDouble(o.toString()));
                } else {
                    field.set(t, o);
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return t;
    }


    public static <T> List<T> parseArray(String text, Class<T> clazz) {
        Object o = preParse(text);
        return parseArray((List) o, clazz);
    }

    private static <T> List<T> parseArray(List<Object> list, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        for (Object o : list) {
            if (o instanceof Map) {
                result.add(parseObject((Map<String, Object>) o, clazz));
            } else {
                result.add((T) o);
            }
        }
        return result;
    }


    /**
     * 将文件解析成抽象语法树
     * @param text
     * @return
     */
    private static Object preParse(String text) {
        CharStream input = CharStreams.fromString(text);
        JSONLexer lexer = new JSONLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        JSONParser parser = new JSONParser(tokens);
        parser.setBuildParseTree(true);
        ParseTree tree = parser.json();
        JSONObjectVisitor visitor = new JSONObjectVisitor();
        return visitor.visit(tree);
    }

    public static void main(String[] args) {
        String js = "{\n" +
                "    \"description\" : null,\n" +
                "    \"logs\" : [{\"level\":\"verbose\", \"dir\":\"/var/log\"},{\"level\":\"verbose1\", \"dir\":\"/var/log1\"}],\n" +
                "    \"host\" : \"antlr.org\",\n" +
                "    \"admin\": [\"parrt\", \"tombu\"],\n" +
                "    \"aliases\": [],\n" +
                "    \"alive\": true,\n" +
                "    \"age\": 100,\n" +
                "    \"amount\": 1.0\n" +
                "}";

        String js2 = "[\n" +
                "  {\n" +
                "    \"level\": \"verbose\",\n" +
                "    \"dir\": \"/var/log\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"level\": \"verbose1\",\n" +
                "    \"dir\": \"/var/log1\"\n" +
                "  }\n" +
                "]";
        String js3 = "[1.0,2.0,3.0]";


        Model model = parseObject(js, Model.class);
        System.out.println(model.getDescription()==null);

        List<Log> logs = parseArray(js2, Log.class);
        System.out.println(logs);


        List<Boolean> rs = parseArray(js3, Boolean.class);
        System.out.println(rs);


    }
}

 

posted @ 2023-04-13 22:20  Mars.wang  阅读(136)  评论(0编辑  收藏  举报