关于fastjson和jackson将json字符串解析成实体的过程(二)
把刚才那些报错的例子,用jackson处理,会发现全部成功,不会报错,测试例子:
那现在看看jackson怎么处理的,进入readValue方法:
进入_jsonFactory.createJsonParser(content):
其实就是根据json字符串转换成一个流,并生成一个jsonParser:
而TypeFactory.type(valueType)方法会生成一个jackson的simple type,例子里是person.class,具体截图:
然后进入_readMapAndClose方法:
具体看
DeserializationConfig cfg = copyDeserializationConfig();
DeserializationContext ctxt = _createDeserializationContext(jp, cfg);
result = _findRootDeserializer(cfg, valueType).deserialize(jp, ctxt);
这三行代码。1是拷贝了反序列化的配置,2是根据配置和上面的ReaderBasedParser,生成一个反序列化的上下文对象,3是先根据配置和所传的对象类型找到对应的反序列化器,感觉这里的逻辑和fastjson很像:
然后具体解析就是deserialize方法了:
public final Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
JsonToken t = jp.getCurrentToken();
if(t == JsonToken.START_OBJECT)
{
jp.nextToken();
return deserializeFromObject(jp, ctxt);
}
static class _cls1
{
static final int $SwitchMap$org$codehaus$jackson$JsonToken[];
static final int $SwitchMap$org$codehaus$jackson$JsonParser$NumberType[];
static
{
$SwitchMap$org$codehaus$jackson$JsonParser$NumberType = new int[org.codehaus.jackson.JsonParser.NumberType.values().length];
try
{
$SwitchMap$org$codehaus$jackson$JsonParser$NumberType[org.codehaus.jackson.JsonParser.NumberType.INT.ordinal()] = 1;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonParser$NumberType[org.codehaus.jackson.JsonParser.NumberType.LONG.ordinal()] = 2;
}
catch(NoSuchFieldError ex) { }
$SwitchMap$org$codehaus$jackson$JsonToken = new int[JsonToken.values().length];
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_STRING.ordinal()] = 1;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_NUMBER_INT.ordinal()] = 2;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_NUMBER_FLOAT.ordinal()] = 3;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_EMBEDDED_OBJECT.ordinal()] = 4;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_TRUE.ordinal()] = 5;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.VALUE_FALSE.ordinal()] = 6;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.START_ARRAY.ordinal()] = 7;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.FIELD_NAME.ordinal()] = 8;
}
catch(NoSuchFieldError ex) { }
try
{
$SwitchMap$org$codehaus$jackson$JsonToken[JsonToken.END_OBJECT.ordinal()] = 9;
}
catch(NoSuchFieldError ex) { }
}
}
switch(_cls1..SwitchMap.org.codehaus.jackson.JsonToken[t.ordinal()])
{
case 1: // '\001'
return deserializeFromString(jp, ctxt);
case 2: // '\002'
case 3: // '\003'
return deserializeFromNumber(jp, ctxt);
case 4: // '\004'
return jp.getEmbeddedObject();
case 5: // '\005'
case 6: // '\006'
case 7: // '\007'
return deserializeUsingCreator(jp, ctxt);
case 8: // '\b'
case 9: // '\t'
return deserializeFromObject(jp, ctxt);
}
throw ctxt.mappingException(getBeanClass());
}
会先去获取当前的JSONToken值,解析一开始都是JsonToken.START_OBJECT,所以走jp.nextToken()方法,调用的是ReaderBasedParser.nextToken():
public JsonToken nextToken()
throws IOException, JsonParseException
{
if(_currToken == JsonToken.FIELD_NAME)
return _nextAfterName();
if(_tokenIncomplete)
_skipString();
int i = _skipWSOrEnd();
if(i < 0)
{
close();
return _currToken = null;
}
_tokenInputTotal = (_currInputProcessed + (long)_inputPtr) - 1L;
_tokenInputRow = _currInputRow;
_tokenInputCol = _inputPtr - _currInputRowStart - 1;
_binaryValue = null;
if(i == 93)
{
if(!_parsingContext.inArray())
_reportMismatchedEndMarker(i, '}');
_parsingContext = _parsingContext.getParent();
return _currToken = JsonToken.END_ARRAY;
}
if(i == 125)
{
if(!_parsingContext.inObject())
_reportMismatchedEndMarker(i, ']');
_parsingContext = _parsingContext.getParent();
return _currToken = JsonToken.END_OBJECT;
}
if(_parsingContext.expectComma())
{
if(i != 44)
_reportUnexpectedChar(i, (new StringBuilder()).append("was expecting comma to separate ").append(_parsingContext.getTypeDesc()).append(" entries").toString());
i = _skipWS();
}
boolean inObject = _parsingContext.inObject();
if(inObject)
{
String name = _parseFieldName(i);
_parsingContext.setCurrentName(name);
_currToken = JsonToken.FIELD_NAME;
i = _skipWS();
if(i != 58)
_reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
i = _skipWS();
}
JsonToken t;
switch(i)
{
case 34: // '"'
_tokenIncomplete = true;
t = JsonToken.VALUE_STRING;
break;
case 91: // '['
if(!inObject)
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
t = JsonToken.START_ARRAY;
break;
case 123: // '{'
if(!inObject)
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
t = JsonToken.START_OBJECT;
break;
case 93: // ']'
case 125: // '}'
_reportUnexpectedChar(i, "expected a value");
// fall through
case 116: // 't'
_matchToken(JsonToken.VALUE_TRUE);
t = JsonToken.VALUE_TRUE;
break;
case 102: // 'f'
_matchToken(JsonToken.VALUE_FALSE);
t = JsonToken.VALUE_FALSE;
break;
case 110: // 'n'
_matchToken(JsonToken.VALUE_NULL);
t = JsonToken.VALUE_NULL;
break;
case 45: // '-'
case 48: // '0'
case 49: // '1'
case 50: // '2'
case 51: // '3'
case 52: // '4'
case 53: // '5'
case 54: // '6'
case 55: // '7'
case 56: // '8'
case 57: // '9'
t = parseNumberText(i);
break;
default:
t = _handleUnexpectedValue(i);
break;
}
if(inObject)
{
_nextToken = t;
return _currToken;
} else
{
_currToken = t;
return t;
}
}
这个方法很重要,就是通过遍历json字符串,来获取分隔符,根据分隔符来获取key值,判断字符的方法是int i = _skipWSOrEnd():
然后回到上个方法,看这部分:
进入_parseFieldName方法:
这个主要是获取key值,也就是字段名,_inputPtr是字符串当前下标,_inputEnd是字符串的总长度,_inputBuffer是该json的字符数组
if(ch == 34){
int start = _inputPtr;
_inputPtr = ptr + 1;
return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
}
break;
如果字符是双引号(第二个),则返回该字段名。
这个方法也是判断字符,同理。
最后部分:
JsonToken t;
switch(i)
{
case 34: // '"'
_tokenIncomplete = true;
t = JsonToken.VALUE_STRING;
break;
case 91: // '['
if(!inObject)
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
t = JsonToken.START_ARRAY;
break;
case 123: // '{'
if(!inObject)
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
t = JsonToken.START_OBJECT;
break;
case 93: // ']'
case 125: // '}'
_reportUnexpectedChar(i, "expected a value");
// fall through
case 116: // 't'
_matchToken(JsonToken.VALUE_TRUE);
t = JsonToken.VALUE_TRUE;
break;
case 102: // 'f'
_matchToken(JsonToken.VALUE_FALSE);
t = JsonToken.VALUE_FALSE;
break;
case 110: // 'n'
_matchToken(JsonToken.VALUE_NULL);
t = JsonToken.VALUE_NULL;
break;
case 45: // '-'
case 48: // '0'
case 49: // '1'
case 50: // '2'
case 51: // '3'
case 52: // '4'
case 53: // '5'
case 54: // '6'
case 55: // '7'
case 56: // '8'
case 57: // '9'
t = parseNumberText(i);
break;
default:
t = _handleUnexpectedValue(i);
break;
}
if(inObject)
{
_nextToken = t;
return _currToken;
} else
{
_currToken = t;
return t;
}
就是根据当前字符来获取JsonToken的值,并传递给_nextToken或者_currToken。
返回BeanDeserializer.deserialize方法,进入deserializeFromObject(jp, ctxt),这个就是解析最主要的方法:
public Object deserializeFromObject(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
if(_defaultConstructor == null)
{
if(_propertyBasedCreator != null)
return _deserializeUsingPropertyBased(jp, ctxt);
if(_delegatingCreator != null)
return _delegatingCreator.deserialize(jp, ctxt);
if(_beanType.isAbstract())
throw JsonMappingException.from(jp, (new StringBuilder()).append("Can not instantiate abstract type ").append(_beanType).append(" (need to add/enable type information?)").toString());
else
throw JsonMappingException.from(jp, (new StringBuilder()).append("No suitable constructor found for type ").append(_beanType).append(": can not instantiate from JSON object (need to add/enable type information?)").toString());
}
Object bean = constructDefaultInstance();
for(; jp.getCurrentToken() != JsonToken.END_OBJECT; jp.nextToken())
{
String propName = jp.getCurrentName();
jp.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName);
if(prop != null)
{
try
{
prop.deserializeAndSet(jp, ctxt, bean);
}
catch(Exception e)
{
wrapAndThrow(e, bean, propName, ctxt);
}
continue;
}
if(_ignorableProps != null && _ignorableProps.contains(propName))
{
jp.skipChildren();
continue;
}
if(_anySetter != null)
try
{
_anySetter.deserializeAndSet(jp, ctxt, bean, propName);
}
catch(Exception e)
{
wrapAndThrow(e, bean, propName, ctxt);
}
else
handleUnknownProperty(jp, ctxt, bean, propName);
}
return bean;
}
生成了一个object,然后根据JsonToken值循环,当JsonToken.END_OBJECT时候结束,当JsonToken改为FIELD_NAME,获取当前的key值,然后循环调用jp.nextToken(),JsonToken改为STRING_VALUE,拿到json字符串的value值,根据反射拿到setter字段名的方法,调用prop.deserializeAndSet(jp, ctxt, bean)给属性赋值。所以这跟你json字符串末尾是什么符号并没什么关系,它是面向对象的思想。
这里对value为null也作了处理:
后面就没什么了,返回bean,清除资源之类的收尾工作。
jackson测试版本比较老,1.7.6,我在网上查的文档是1.9.9,所以这里有部分方法最新版没有。
所以经过这次查看源码,发现jackson还是比较全面的,推荐使用。