实例解析Json反序列化之ObjectMapper(自定义实现反序列化方法)

实例解析Json反序列化之ObjectMapper(自定义实现反序列化方法)

本文主要介绍实例解析json反序列化的ObjectMapper,以及Json自定义序列化的方法。有需要的朋友可以了解一下。

对于服务器端开发人员来说,调用第三方接口获取数据,将其转换为代理并返回给客户端几乎是家常便饭。一般第三方接口返回的数据类型是json格式,而服务器开发者需要将json格式的数据转换成对象,然后进行处理封装返回给客户端。

当效率不是特别需要考虑的时候(thrift和protobuffer可以用于搜索、缓存等。),我们通常选择jackson包中的ObjectMapper类对json字符串进行反序列化,得到相应的对象。通常选择readvalue (string content,classvaluetype)方法进行反序列化。

ObjectMapper的readValue方法将json字符串反序列化为对象,如下所示:根据传入的json字符串和目标对象类型创建json parse和JavaType,然后生成DeserializationConfig、DeserializationContext和JsonDeserializer。JsonDeserializer的实现类决定了解析的类型(Bean、Map、String等。)将被执行。JsonParse存储要解析的字符串和其他信息。在解析的过程中,通过token判断当前匹配的类型(比如遇到{,判断为对象类型的起始位置;当遇到[,判断为set类型的起始位置]时,一旦类型确定,就跳转到对应的反序列化类进行处理,得到结果,然后令牌移回来,再解析下一个字符串。它可以被视为递归解析。当它被token判断为对象时,会跳转到BeanDeserializer进行解析,然后遍历对象的所有字段。如果字段是字符串,会跳转到StringDeserializer进行解析;如果字段是数组,它将跳转到CollectionDeserializer中进行解析,直到解析完整个字符串。也可以看做是一种相似性,是对树的深度遍历,相当好理解。

下面简单介绍一下ObjectMapper的readValue方法的反序列化过程:

a:通过json串和对象类型得到JsonParser和JavaType。

public T T readValue(字符串内容,ClassT valueType)

抛出IOException、JsonParseException、JsonMappingException

{

return(T)_ readMapAndClose(_ JSON factory . create parser(content),_ type factory . construct type(value type));

}

//获取json解析器,其中包含解析后的字符串

公共JsonParser createParser(字符串内容)引发IOException,JsonParseException {

final int strLen=content . length();

//实际上,让我们将它用于中等大小的内容,最多64kB块(32kb字符)

if (_inputDecorator!=null || strLen0x8000 ||!canUseCharArrays()) {

//仅包装在读取器中比扩展InputDecorator更容易;或者,如果内容

//太长了,我们无法复制

返回create parser(new string reader(content));

}

io context ctxt=_ create context(content,true);

char[]buf=ctxt . alloctokenbuffer(strLen);

content.getChars(0,strLen,buf,0);

return _createParser(buf,0,strLen,ctxt,true);

}

//将要解析的类型转换为JavaType类型

公共JavaType构造类型(类型类型){

return _constructType(类型,null);

}

受保护的JavaType _constructType(类型类型,类型绑定上下文)

{

JavaType resultType

//简单类?

if (type instanceof Class?) {

resultType=_fromClass((Class?)类型、上下文);

}

//但如果不是,需要开始解析。

else if(type instance of parameterized type){

result type=_ from param type((parameterized type)类型,上下文);

}

else if(type instance of JavaType){//[问题#116]

return (JavaType)类型;

}

else if(type instance of genericaraytype){

result type=_ from array type((genericaraytype)类型,上下文);

}

TypeVariable的type instanceof?) {

result type=_ from variable((type variable?)类型、上下文);

}

else if(通配符类型的类型实例){

结果类型=_通配符((通配符类型)类型,上下文);

}否则{

//健全性检查

抛出新的IllegalArgumentException(无法识别的类型:((type==null)?“[null]”:类型。tostring()));

}

如果(_修饰符!=null!resultType.isContainerType()) {

for(类型修饰符mod:_ modifiers){

结果类型=mod。修改类型(结果类型、类型、上下文、this);

}

}

返回结果类型;

}

b、获取反序列化配置对象和上下文对象,进行第一步的序列化操作。

protected Object _ readMapAndClose(JsonParser jp,JavaType valueType)

抛出IOException、JsonParseException、JsonMappingException

{

尝试{

对象结果;

反序列化配置CFG=getdeserizationconfig();

反序列化上下文ctxt=createdisationcontext(jp,CFG);

//依据值类型得到反序列化的解析器

//对象对应的是豆反序列化程序映射对应的是映射反序列化程序

jsondeserializer对象deser=_ findRootDeserializer(ctxt,值类型);

if (cfg.useRootWrapping()) {

result=_ unwandeserialize(jp,ctxt,cfg,valueType,deser);

}否则{

//如果是对象,则调到豆解串器类中进行解析

result=deser.deserialize(jp,ctxt);

}

ctxt。checkunresolvedobjectid();

}

//也需要使用令牌

jp。clearcurrenttoken();

返回结果;

}最后{

尝试{

jp。close();

} catch (IOException ioe) { }

}

}

c、跳入到BeanDeserializer类中。

下面以豆解串器为例进行讲解:

@覆盖

公共对象反序列化(JsonParser p,反序列化上下文ctxt)

抛出IOException

{

JsonToken t=p . getcurrenttoken();

//常见情况优先

if (t==JsonToken .START_OBJECT) { //TODO:在2.6中,使用p.hasTokenId()

if (_vanillaProcessing) {

返回vanillaDeserialize(p,ctxt,p . nexttoken());

}

p。nexttoken();

if(_对象阅读器!=null) {

返回deserializeWithObjectId(p,ctxt);

}

返回deserializeFromObject(p,ctxt);

}

return _deserializeOther(p,ctxt,t);

}

/**

*简化版本,仅在没有"特殊"时使用

*功能已启用。

*/

私有最终对象vanillaDeserialize(JsonParser p,

反序列化上下文ctxt,JsonToken t)

抛出IOException

{

最终对象bean=_ value实例化器。createusingdefault(ctxt);

//[databind#631]:分配可由自定义序列化程序访问的当前值

p。setcurrentvalue(bean);

for(;t==JsonToken .FIELD _ NAMEt=p.nextToken()) {

string propName=p . getcurrentname();

p。nexttoken();

如果(!_ bean属性。findeserialdandset(p,ctxt,bean,propName)) {

handleUnknownVanilla(p,ctxt,bean,propName);

}

}

回豆;

}

/**

*尝试查找具有给定名称的属性的便利方法,以及

*如果找到,请调用{ @ link SettableBeanProperty # deserialidandset }

*开启它,并返回真实的或者,如果没有找到,则返回错误.

*还要注意,如果尝试反序列化,可能会出现异常

*在必要时被包装,因此调用方不需要处理它们。

*

* @从2.5开始

*/

公共布尔findeserialdandset(JSON解析器p,反序列化上下文ctxt,

对象豆子,字符串键)抛出IOException

{

如果(_不区分大小写){

钥匙=钥匙。tolowercase();

}

int index=key。hashcode()_哈希掩码;

bucket bucket=_ buckets[index];

//让我们展开第一次查找,因为它在90 %的情况下为空或匹配

if (bucket==null) {

返回错误的

}

//主要我们只做身份比较,因为密钥应该被保留

if (bucket.key==key) {

尝试{

水桶。价值。deserialidandset(p,ctxt,bean);

} catch(异常e) {

wrapAndThrow(e,bean,key,ctxt);

}

返回真实的

}

return _ findeserialidandset 2(p,ctxt,bean,key,index);

}

方法属性

@覆盖

public void deserialidandset(JsonParser jp,DeserializationContext ctxt,

对象实例)引发IOException

{

Object value=deserialize(jp,ctxt);

尝试{

//将得到的结果放入反序列化对应的对象中

_setter.invoke(实例,值);

} catch(异常e) {

_throwAsIOE(e,value);

}

}

公共最终对象反序列化抛出IOException

{

JsonToken t=p . getcurrenttoken();

if (t==JsonToken .VALUE_NULL) {

return (_nullProvider==null)?null:_ null提供程序。空值(ctxt);

}

if (_valueTypeDeserializer!=null) {

return _ value deserialir。deserialiwithtype(p,ctxt,_ valueTypeDeserializer

}

return _ value反序列化器。反序列化(p,ctxt);

}

//如果继承了JsonDeserializer类重写了沙漠方法,则会跳转到对应注入的类中进行处理

//不出意外的话最后都会调用反序列化上下文的readValue(JsonParser p,ClassT类型)方法,然后会根据类型的类型跳转到对应的反序列化类中进行处理。

public T T readValue(JsonParser p,ClassT类型)抛出IOException {

返回readValue(p,getTypeFactory().构造类型(type));

}

@SuppressWarnings(未选中)

public T T readValue(JsonParser p,JavaType类型)抛出IOException {

//得到最终解析的类型,映射列表字符串。

jsondeserializer对象deser=findRootValueDeserializer(类型);

if (deser==null) {

}

return (T) deser.deserialize(p,this);

}

//例如这里如果是一个地图,则会调用映射反序列化程序的使沙漠化方法得到最后的返回结果。

//对于集合类,会通过代币按照顺序解析生成一个个的集合对象并放入集合中。

JsonToken t;

while ((t=p.nextToken())!=JsonToken .END_ARRAY) {

尝试{

对象值;

if (t==JsonToken .VALUE_NULL) {

值=值des。getnullvalue();

} else if (typeDeser==null) {

value=valueDes.deserialize(p,ctxt);

}否则{

值=值des。deserializewithtype(p,ctxt,typeDeser);

}

if (referringAccumulator!=null) {

referringAccumulator.add(值);

}否则{

结果.添加(值);

}

} catch(UnresolvedForwardReference引用){

if(referringAccumulator==null){

抛出JsonMappingException。来自(p,"未解析的前向引用,但没有标识信息",引用);

}

引用ref=referringaccumulator。handleunresolvedreference(引用);

reference.getRoid().追加引用(ref);

} catch(异常e) {

抛出jsonmappingexception。wrapwithpath(e,result,result。size());

}

}

返回结果;

在不同的业务场景下,第三方接口返回的数据类型可能会发生变化,比如最初第三方业务代码是使用服务器端编程语言(专业超文本预处理器的缩写)实现的,而与之对接的服务器端也是用服务器端编程语言(专业超文本预处理器的缩写)实现的。后来,又成立了以Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)为开发语言的服务器端开发小组,此时,对接第三方可能会出现问题。第三方返回数据类型的不唯一性,可能会使Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)开发人员无法"正常"反序列化第三方接口返回的json串。例如:第三方接口返回的字段中,当字段为空时,返回的是数组;而字段不为空时,返回的却是对象。这样,那么通过对象映射器进行解析时,就会抛出异常,导致服务器端无法正常将数据返回给客户端。面对这样的问题,可能有以下两种解决方法:

第一种解决方法是对豆中每个字段设置方法内进行判断,当解析字符串是一个数组时,则返回空对象;

当解析的字符串不为空时,就会特别的麻烦,默认情况下,会将Json串解析成一个地图,其中键为豆中字段的名称,值为豆的值。这样,就需要创建一个新的豆子,随后依次从地图中取出对应字段的值,然后再设置到豆中。显然,这种方式很麻烦,一旦第三方字段发生变化时,需要不停地维护这段代码。

第二种解决方法是继承JsonDeserialize,并重写反序列化方法。通过源码可知,JsonDeserializer抽象类是处理反序列化的类,只需在豆类中的字段上加入注解@JsonDeserialize(使用=xxx.class),并且xxx类要继承JsonDeserializer类,且重新对应的反序列化方法,在该方法中进行相应处理即可。在该方法中处理待反序列化字段可能出现的多种不同情况,详情见源码。

这里需要注意的是:当反序列化字段是一个对象,而第三方返回的数据为一个数组时,在重写反序列化方法时,如果判断出当前代币指向的是一个数组,而此时需得到空对象。此时,不能直接返回空对象,必须调用读取值方法,目的是将代币移动到正确的位置,否则,将创建一些奇怪的对象。

对于第二种解决方法,下面举例说明:

包com.string

导入Java。util。地图;

导入com。更快的XML。杰克逊。数据绑定。注释。JSON反序列化;

公共类注释{

公共字符串id;

@ JsonDeserialize(使用=ImgPackSerializer.class)

公共映射字符串,字符串imgPack

@ JsonDeserialize(使用=CoopSerializer.class)

公共合作社;

public Coop getCoop() {

返回笼子

}

public void setCoop(Coop coop) {

this.coop=coop

}

公共映射字符串,字符串getimpack(){

返回imgPack

}

public void setImgPack(MapString,String imgPack) {

这个。img包=img包;

}

公共字符串getId() {

返回id;

}

公共void集合id(字符串id) {

this.id=id

}

}

类别合作

公共整数年龄;

公共整数getAge() {

回归年龄;

}

公共空的存储(整数年龄){

this.age=年龄;

}

}

包com.string

导入Java。io。io异常;

导入Java。util。列表;

导入Java。util。地图;

导入com。更快的XML。杰克逊。核心。JSON解析器;

导入com。更快的XML。杰克逊。核心。jsonprocessingexception

导入com。更快的XML。杰克逊。核心。jsontoken

导入com。更快的XML。杰克逊。数据绑定。沙漠化语境;

导入com。更快的XML。杰克逊。数据绑定。JSON反序列化器;

导入com。更快的XML。杰克逊。数据绑定。对象映射器;

公共类TestJson {

静态对象映射器OBJECT _ MAPPER=新对象映射器();

公共静态void main(String[] args) {

字符串s={code:1 , comm :[{ img pack :{ ABC : ABC }, coop:[]}], name : car } ;

尝试{

响应读取值=对象映射器。读取值,响应。类);

系统。呃。println(读取值。tostring());

} catch (IOException e) {

e。printstacktrace();

}

}

}

类别响应{

公共字符串代码;

公共列表comm comm

公共字符串名称;

公共字符串getName() {

返回名称;

}

公共void集合名称(字符串名){

this.name=name

}

公共字符串getCode() {

返回代码;

}

公共void setCode(字符串代码){

this.code=代码

}

public ListComment getComm() {

返回通信

}

public void setComm(列表注释comm){

this.comm=comm

}

}

类合作串行器扩展了JsonDeserializerCoop {

@覆盖

公共合作反序列化(JsonParser jp,反序列化上下文ctxt)

引发IOException,JsonProcessingException {

JsonToken当前令牌=jp。get current token();

if (currentToken==JsonToken .开始_数组){

//返回null//错误可能会创建更多对象

//jp。nexttoken();//错误

return ctxt.readValue(jp,Object.class)==null?null:null;

} else if(current token==JsonToken .开始_对象){

return (Coop) ctxt.readValue(jp,Coop。类);

}

返回空

}

}

ImgPackSerializer类扩展JsonDeserializerMapString,String {

@覆盖

公共映射字符串,字符串反序列化(JsonParser jp,

反序列化上下文ctxt)抛出IOException,

JsonProcessingException {

JsonToken当前令牌=jp。get current token();

if (currentToken==JsonToken .开始_数组){

return ctxt.readValue(jp,Object.class)==null?null:null;

} else if(current token==JsonToken .开始_对象){

return (MapString,String) ctxt.readValue(jp,map。类);

}

返回空

}

}

总结

以上就是本文关于实例解析Json反序列化之对象映射器(自定义实现反序列化方法)的全部内容,希望对大家有所帮助。欢迎大家参阅本站其他专题,有什么问题可以留言,小编会及时回复大家的。

实例解析Json反序列化之ObjectMapper(自定义实现反序列化方法)