2021SC@SDUSC
DefaultJSONParser本质上是一个反序列化组合器,集成了Feature,LexerBase,ParserConfig等的实例,这些都在前文中有提及。这篇文章主要介绍DefaultJSONParser提供的一些方法,了解它在FastJSON反序列化过程中的作用机制和原理。
目录
- 构造方法介绍
- public void acceptType(String typeName)接收类型
- public void parseArray(Type type, Collection array, Object fieldName)对数组进行解析
- public void parseExtra(Object object, String key) 对额外字段进行解析
- 总结
构造方法介绍
简要看一下这个类同名的几个构造方法:
不得不说,FastJSON的作者在类型的构造上十分严谨,详细考虑到了各种可能出现的情况,并针对每种情况设计了相应的方法。只看方法签名就可以得知,构造方法实际上在尝试对这个类中的ParserConfig和JSONLexer进行实例化,且这两个参数可以单独出现在参数表中而互不干涉,符合我们之前的分析。
查看方法体得知前六个方法最终都指向了第七个方法,这里我们看一下它的代码:
public DefaultJSONParser(Object input, JSONLexer lexer, ParserConfig config) {
this.dateFormatPattern = JSON.DEFFAULT_DATE_FORMAT;
this.contextArrayIndex = 0;
this.resolveStatus = 0;
this.extraTypeProviders = null;
this.extraProcessors = null;
this.fieldTypeResolver = null;
this.lexer = lexer;
this.input = input;
this.config = config;
this.symbolTable = config.symbolTable;
int ch = lexer.getCurrent();
if (ch == '{') {
lexer.next();
((JSONLexerBase)lexer).token = 12;
} else if (ch == '[') {
lexer.next();
((JSONLexerBase)lexer).token = 14;
} else {
lexer.nextToken();
}
}
显然这个方法除了对一些对象进行初始化之外,还对待解析的字符串(包含在lexer中)的第一个字符进行了相应的判断。如果是(
或者[
,则直接将lexer的next后移一位。为了方便查看Token号,我们搬出Token对应的表。
public static final int ERROR = 1;
public static final int LITERAL_INT = 2;
public static final int LITERAL_FLOAT = 3;
public static final int LITERAL_STRING = 4;
public static final int LITERAL_ISO8601_DATE = 5;
public static final int TRUE = 6;
public static final int FALSE = 7;
public static final int NULL = 8;
public static final int NEW = 9;
public static final int LPAREN = 10;
public static final int RPAREN = 11;
public static final int LBRACE = 12;
public static final int RBRACE = 13;
public static final int LBRACKET = 14;
public static final int RBRACKET = 15;
public static final int COMMA = 16;
public static final int COLON = 17;
public static final int IDENTIFIER = 18;
public static final int F
IELD_NAME = 19;
public static final int EOF = 20;
public static final int SET = 21;
public static final int TREE_SET = 22;
public static final int UNDEFINED = 23;
显然12和14对应的就是(
和[
。
public void acceptType(String typeName)接收类型
先看代码:
public void acceptType(String typeName) {
JSONLexer lexer = this.lexer;
lexer.nextTokenWithColon();
//判断下一个token是不是String类型
if (lexer.token() != 4) {
//不是,抛出JSON异常并显示类型不匹配
throw new JSONException("type not match error");
}
//是String,判断是否与lexer的String值匹配
else if (typeName.equals(lexer.stringVal())) {
lexer.nextToken();
if (lexer.token() == 16) {
lexer.nextToken();
}
} else {
throw new JSONException("type not match error");
}
}
这个没有返回值的方法的作用就是接收一个类型名并进行判断其是否合法,第一次判断是否是String类型,第二次判断是否与lexer的类型相同,两次判断通过后,对lexer进行一位后移后返回。判断不通过则抛出异常给上层调用者处理。
public void parseArray(Type type, Collection array, Object fieldName)对数组进行解析
这个方法同以往解析单个json字符串不同,它用于解析json数组。这里就涉及到了一个循环解析的过程,因为json数组往往包含多个json对象,需要考虑初始化、解析效率、解析正确性等诸多问题。
public void parseArray(Type type, Collection array, Object fieldName) {
//SET或TreeSET类型,直接后移一位
if (this.lexer.token() == 21 || this.lexer.token() == 22) {
this.lexer.nextToken();
}
//第一个token不是左中括号[,抛出异常
if (this.lexer.token() != 14) {
throw new JSONException("exepct '[', but " + JSONToken.name(this.lexer.token()) + ", " + this.lexer.info());
} else {
//否则生成相应的反序列化器,根据type来作出决定
ObjectDeserializer deserializer = null;
if (Integer.TYPE == type) {
deserializer = IntegerCodec.instance;
this.lexer.nextToken(2);
} else if (String.class == type) {
deserializer = StringCodec.instance;
this.lexer.nextToken(4);
} else {
deserializer = this.config.getDeserializer(type);
this.lexer.nextToken(((ObjectDeserializer)deserializer).getFastMatchToken());
}
//初始化上下文
ParseContext context = this.context;
this.setContext(array, fieldName);
try {
int i = 0;
//循环解析,这个方法的关键部分,在这里将对json数组中每个json字符串进行解析,生成相应的对象并放入容器中
while(true) {
if (this.lexer.isEnabled(Feature.AllowArbitraryCommas)) {
while(this.lexer.token() == 16) {
this.lexer.nextToken();
}
}
if (this.lexer.token() == 15) {
break;
}
Object val;
if (Integer.TYPE == type) {
val = IntegerCodec.instance.deserialze(this, (Type)null, (Object)null);
array.add(val);
} else if (String.class == type) {
String value;
if (this.lexer.token() == 4) {
value = this.lexer.stringVal();
this.lexer.nextToken(16);
} else {
Object obj = this.parse();
if (obj == null) {
value = null;
} else {
value = obj.toString();
}
}
array.add(value);
} else {
if (this.lexer.token() == 8) {
this.lexer.nextToken();
val = null;
} else {
val = ((ObjectDeserializer)deserializer).deserialze(this, type, i);
}
array.add(val);
this.checkListResolve(array);
}
if (this.lexer.token() == 16) {
this.lexer.nextToken(((ObjectDeserializer)deserializer).getFastMatchToken());
}
++i;
}
} finally {
this.setContext(context);
}
this.lexer.nextToken(16);
}
}
代码中可见,该方法先进行一系列的判断。首先确定是否是特殊类型的json数组,即set形式或者treeset形式,并对这种格式进行移位处理。做完这一步后可以确定如果是一个合法的json数组字符串,以一个字符即token必定是[
,对其判断,如果不是,直接抛出异常。这几步判断完成之后,可以确定是一个合法的json数组了,接下来根据传入的type字段表示的类型,初始化相应的反序列化器,初始化上下文之后,开始正式的循环解析。最后将每个生成的对象放入collection容器中,调用者接收。
public void parseExtra(Object object, String key) 对额外字段进行解析
public void parseExtra(Object object, String key) {
JSONLexer lexer = this.lexer;
lexer.nextTokenWithColon();
Type type = null;
ExtraTypeProvider extraProvider;
if (this.extraTypeProviders != null) {
for(Iterator var5 = this.extraTypeProviders.iterator(); var5.hasNext(); type = extraProvider.getExtraType(object, key)) {
extraProvider = (ExtraTypeProvider)var5.next();
}
}
Object value = type == null ? this.parse() : this.parseObject(type);
if (object instanceof ExtraProcessable) {
ExtraProcessable extraProcessable = (ExtraProcessable)object;
extraProcessable.processExtra(key, value);
} else {
if (this.extraProcessors != null) {
Iterator var9 = this.extraProcessors.iterator();
while(var9.hasNext()) {
ExtraProcessor process = (ExtraProcessor)var9.next();
process.processExtra(object, key, value);
}
}
}
}
这个方法首先获取lexer对象,然后实例化一个ExtraTypeProvider对象用于解析额外字段。最后调用extraProcessable.processExtra(key, value)方法,将key代表的需要解析的额外字段进行解析,并用value对象保存解析后的结果。这个方法用的不多,但是当相关需求出现时,它是必不可少的。试想,对于json字符串中的一个token,如果你想单独解析而不按照默认的过程解析,就需要用到这个方法,而且无法被其他方法替代。
总结
这篇分析了DefaultJSONParser提供的几个不太寻常的方法,这些方法的共同作用,保证了FastJSON既能正确而高效地对常见的json字符串和字符串数组进行解析,又保证了它不会忽略任何潜在的不太常见的解析请求。正是其功能的全面性,使得FastJSON比常规的json工具更受欢迎。