分析json的方式有很多,使用antlr做json的分析在性能上肯定不怎么好,比较涉及到语法语义的分析,同时把json转成java对象的话,那么肯定要基于ast去做,所以在性能上肯定没有原生的好,这里只是提供一种解决思路,比较做原生的json分析,肯定用antlr的话更加的直观一点,下面是antlr的两个分析文件的内容
首先是普通解析器的语法文件
grammar JSON;
?options
?{
backtrack=true;?
memoize=true;
output=AST;
ASTLabelType=CommonTree;?
k=1;
?}
? ??
?tokens
?{
? ? ? ? ?OBJECT;
? ? ? ? ?ELEMENT;
? ? ? ? ?ARRAY;
? ? ? ? ?STRING;
? ? ? ? ?INTEGER;
? ? ? ? ?DOUBLE;
?}
?
?@lexer::header
?{
?
?package com.test.json.antlr3;
?}
?
?@header
?{
?package com.test.json.antlr3;
?}
?
@lexer::members{
?
?
List errorList = new ArrayList();
?
?public void displayRecognitionError(String[] tokenNames,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RecognitionException e) {
? ? ? ? String hdr = getErrorHeader(e);
? ? ? ? String msg = getErrorMessage(e, tokenNames);
? ? ? ? errorList.add(hdr+" ? ?"+msg);
? ?
? ? }
?
}
?
?
?
@members
{
?
?
List errorList = new ArrayList();
?
?public void displayRecognitionError(String[] tokenNames,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RecognitionException e) {
? ? ?
? ? ? ? String hdr = getErrorHeader(e);
? ? ? ? String msg = getErrorMessage(e, tokenNames);
? ?
? ? ? ? errorList.add(hdr+" ? ?"+msg);
? ?
? ? }
?
}
?
?
?
?// lexer rules
?Colon: ':';
?Comma: ',';
?LBrace: '{';
?RBrace: '}';
?LBracket: '[';
?RBracket: ']';
?fragment Dot: '.';
?TRUE: ?'true';
?FALSE: 'false';
?NULL: 'null';
?DOUBLE_QUOTES :'"';
?
?
?fragment Digit: '0' .. '9';
?fragment HexDigit: ('0' .. '9' | 'A' .. 'F' | 'a' .. 'f');
?fragment UnicodeChar: ~('"'| '\\' );
?fragment StringChar : ?('a'..'z'|'A'..'Z'|'0'..'9'|'_')+;
?
?fragment EscapeSequence
? ? ? ? ?: '\\' ('\"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' | 'u' HexDigit HexDigit HexDigit HexDigit)
? ? ? ? ?;
?
?fragment Int: '-'? ('0' | '1'..'9' Digit*);
?fragment Frac: Dot Digit+;
?fragment Exp: ('e' | 'E') ('+' | '-')? Digit+;
?
?WhiteSpace: (' ' | '\r' | '\t' | '\u000C' | '\n') { $channel=HIDDEN; };
?
?
?Integer: Int;
?Double: ?Int (Frac Exp? | Exp);
?StringLiteral
? ? : ?'"' ( EscapeSequence | ~('\\'|'"') )* '"'
? ? ;
?
?String: DOUBLE_QUOTES StringLiteral* DOUBLE_QUOTES;
?
? ? ?
?IDENTIFIER
:
StringChar*
;
?
?
?jsonObject
? ? ? ? ?: object
? ? ? ? ?;
? ? ? ? ?
?jsonArray
? ? ? ? ?: array
? ? ? ? ?; ? ? ??
?
?
?object
? ? ? ? ?: LBrace (objectElement (Comma objectElement)*)? RBrace
? ? ? ? ?;
? ? ? ? ?
?objectElement
? ? ? ? ?:?
? ? ? ? ? ?(StringLiteral
? ? ? ? ? ?|
? ? ? ? ? ?IDENTIFIER
? ? ? ? ? ?)
? ? ? ? ? ? Colon value
? ? ? ? ?;?
? ? ? ?
?
? ? ? ?
?array
? ? ? ? ?: LBracket value (Comma value)* RBracket
? ? ? ? ?;
?
? ? ? ? ?
?value
? ? ? ? ?: StringLiteral?
? ? ? ? ?| Integer
? ? ? ? ?| Double
? ? ? ? ?| object ?
? ? ? ? ?| array ?
? ? ? ? ?| TRUE ??
? ? ? ? ?| FALSE
? ? ? ? ?| NULL
? ? ? ? ?;
antlr3的tree grammar的内容
?tree grammar JSONWalker;
?options
?{
backtrack=true;?
memoize=true;
output=AST;
ASTLabelType=CommonTree;?
tokenVocab=JSON;?
k=1;
?}
? ??
?
?
@header {
package com.test.json.antlr3;
}
?
?
?jsonObject
? ? ? ? ?: object
? ? ? ? ?;
? ? ? ? ?
?jsonArray
? ? ? ? ?: array
? ? ? ? ?; ? ? ??
?
?object
? ? ? ? ?: LBrace (objectElement (Comma objectElement)*)? RBrace
? ? ? ? ? ?-> ^(OBJECT objectElement*)
? ? ? ? ?;
? ? ? ? ?
?objectElement
? ? ? ? ?: (StringLiteral
? ? ? ? ? ?|?
? ? ? ? ? ?IDENTIFIER) Colon value
? ? ? ? ? ? -> ^(ELEMENT StringLiteral? IDENTIFIER? value)
? ? ? ? ?; ? ? ??
? ? ? ? ?
?array
? ? ? ? ?: LBracket value (Comma value)* RBracket
? ? ? ? ? ?-> ^(ARRAY value+)
? ? ? ? ?;
?
? ? ? ? ?
?value
? ? ? ? ?: StringLiteral -> ^(STRING StringLiteral)
? ? ? ? ?| Integer -> ^(INTEGER Integer)
? ? ? ? ?| Double -> ^(DOUBLE Double)
? ? ? ? ?| object ?
? ? ? ? ?| array ?
? ? ? ? ?| TRUE ??
? ? ? ? ?| FALSE
? ? ? ? ?| NULL
? ? ? ? ?;
通过antlr的tool工具生成解析器,为了方便可以写一个ant脚本去实现,具体如下
? ? ? ?? <java classname="org.antlr.Tool"
? ? ? ? ? fork="true"
? ? ? ? failonerror="false"
? ? ? ? ?maxmemory="256m"
? ? ? ? >
? ? ? ? <classpath>
? ? ? ? <pathelement path="${maven}/org/antlr/antlr-complete/3.5.2/antlr-complete-3.5.2.jar" /> ? ? ?
? ? ? ? </classpath>
? ? ? ? <arg value="-o"/>
? ? ? ? <arg value="${projectpath}/src/main/java/com/test/json/antlr3"/>
? ? ? ? <arg value="-print"/>
? ? ? ? <arg value="${projectpath}/grammar/JSON.g"/>
? ? ? ? </java>
? ?
? ?
? ? ? ? <java classname="org.antlr.Tool"
? ? ? ? ? fork="true"
? ? ? ? failonerror="false"
? ? ? ? ?maxmemory="256m"
? ? ? ? >
? ? ? ? <classpath>
? ? ? ? <pathelement path="${maven}/org/antlr/antlr-complete/3.5.2/antlr-complete-3.5.2.jar" /> ? ? ?
? ? ? ? </classpath>
? ? ? ? <arg value="-o"/>
? ? ? ? <arg value="${projectpath}/src/main/java/com/test/json/antlr3"/>
? ? ? ? <arg value="-print"/>
? ? ? ? <arg value="${projectpath}/grammar/JSONWalker.g"/>
? ? ? ? </java>
?
有了ast语法树以后,剩下的就是要做分析,antlr3有两种方式处理ast语法树,一种是编写treeadapter(需要分析token流,对于我来说难度太大),一种是使用默认的,自己去做遍历,遍历的结果有两种一种是Object一种是Array,但是由于这个只是普通的json原生转化需要实例化具体的业务对象中,我采用先生成语法树,然后生成原生的Java的json对象,通过该对象转化到具体的业务对象中。
转化的过程涉及到了java反射,所以在性能优化上可以做一些缓存处理,在反射处理中使用sun里面的unsafer类,得到最后的转化效果代码如下
public static void main(String[] args) {
User user = JSON.parseObject("{username:null,contact:{mobile:\"1123111311\",qq:\"1231001884\",email:\"ceshi@126.com\"},address:[{email:\"test\",qq:\"419001231\"}]}", User.class);
System.out.println(user.getContact().getMobile()+" "+user.getContact().getEmail()+" "+user.getAddress());
}
把json里面的数据转化成user对象,具体实现可以实例代码
?
如果要做测试,加入maven的依赖包
?
? <properties> ? ? ?
? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>?
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> ? ?
? </properties>?
??
? <dependencies>
?<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr-complete</artifactId>
<version>3.5.2</version>
</dependency>
? </dependencies>
只有一个依赖包
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?