基于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); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2022-04-13 图数据库neo4j部署-linux