Gson使用指南4.docx

上传人:b****8 文档编号:23608610 上传时间:2023-05-19 格式:DOCX 页数:13 大小:20.09KB
下载 相关 举报
Gson使用指南4.docx_第1页
第1页 / 共13页
Gson使用指南4.docx_第2页
第2页 / 共13页
Gson使用指南4.docx_第3页
第3页 / 共13页
Gson使用指南4.docx_第4页
第4页 / 共13页
Gson使用指南4.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

Gson使用指南4.docx

《Gson使用指南4.docx》由会员分享,可在线阅读,更多相关《Gson使用指南4.docx(13页珍藏版)》请在冰豆网上搜索。

Gson使用指南4.docx

Gson使用指南4

注:

此系列基于Gson2.4。

本次文章的主要内容:

∙TypeAdapter

∙JsonSerializer与JsonDeserializer

∙TypeAdapterFactory

∙@JsonAdapter注解

∙TypeAdapter与JsonSerializer、JsonDeserializer对比

∙TypeAdapter实例

∙结语

∙后期预告

一、TypeAdapter

TypeAdapter 是Gson自2.0(源码注释上说的是2.1)开始版本提供的一个抽象类,用于接管某种类型的序列化和反序列化过程,包含两个注要方法 write(JsonWriter,T) 和 read(JsonReader) 其它的方法都是final方法并最终调用这两个抽象方法。

1

2

3

4

5

publicabstractclassTypeAdapter{

    publicabstractvoidwrite(JsonWriterout,Tvalue)throwsIOException;

    publicabstractTread(JsonReaderin)throwsIOException;

    //其它final方法就不贴出来了,包括`toJson`、`toJsonTree`、`toJson`和`nullSafe`方法。

}

注意:

TypeAdapter以及JsonSerializer和JsonDeserializer都需要与 GsonBuilder.registerTypeAdapter 示或GsonBuilder.registerTypeHierarchyAdapter配合使用,下面将不再重复说明。

使用示例:

1

2

3

4

5

6

7

Useruser=newUser("怪盗kidou",24);

user.emailAddress="ikidou@";

Gsongson=newGsonBuilder()

        //为User注册TypeAdapter

        .registerTypeAdapter(User.class,newUserTypeAdapter())

        .create();

System.out.println(gson.toJson(user));

UserTypeAdapter的定义:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

publicclassUserTypeAdapterextendsTypeAdapter{

 

    @Override

    publicvoidwrite(JsonWriterout,Uservalue)throwsIOException{

        out.beginObject();

        out.name("name").value(value.name);

        out.name("age").value(value.age);

        out.name("email").value(value.email);

        out.endObject();

    }

 

    @Override

    publicUserread(JsonReaderin)throwsIOException{

        Useruser=newUser();

        in.beginObject();

        while(in.hasNext()){

            switch(in.nextName()){

                case"name":

                    user.name=in.nextString();

                    break;

                case"age":

                    user.age=in.nextInt();

                    break;

                case"email":

                case"email_address":

                case"emailAddress":

                    user.email=in.nextString();

                    break;

            }

        }

        in.endObject();

        returnuser;

    }

}

当我们为User.class 注册了 TypeAdapter之后,只要是操作User.class 那些之前介绍的@SerializedName 、FieldNamingStrategy、Since、Until、Expos通通都黯然失色,失去了效果,只会调用我们实现的UserTypeAdapter.write(JsonWriter,User) 方法,我想怎么写就怎么写。

再说一个场景,在该系列的第一篇文章就说到了Gson有一定的容错机制,比如将字符串 "24" 转成int的24,但如果有些情况下给你返了个空字符串怎么办(有人给我评论问到这个问题)?

虽然这是服务器端的问题,但这里我们只是做一个示范。

int型会出错是吧,根据我们上面介绍的,我注册一个TypeAdapter把序列化和反序列化的过程接管不就行了?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

Gsongson=newGsonBuilder()

        .registerTypeAdapter(Integer.class,newTypeAdapter(){

            @Override

            publicvoidwrite(JsonWriterout,Integervalue)throwsIOException{

                out.value(String.valueOf(value));

            }

            @Override

            publicIntegerread(JsonReaderin)throwsIOException{

                try{

                    returnInteger.parseInt(in.nextString());

                }catch(NumberFormatExceptione){

                    return-1;

                }

            }

        })

        .create();

System.out.println(gson.toJson(100));//结果:

"100"

System.out.println(gson.fromJson("\"\"",Integer.class));//结果:

-1

注:

测试空串的时候一定是"\"\""而不是"",""代表的是没有json串,"\"\""才代表json里的""。

你说这一接管就要管两样好麻烦呀,我明明只想管序列化(或反列化)的过程的,另一个过程我并不关心,难道没有其它更简单的方法么?

当然有!

就是接下来要介绍的JsonSerializer与JsonDeserializer。

二、JsonSerializer与JsonDeserializer

JsonSerializer 和JsonDeserializer 不用像TypeAdapter一样,必须要实现序列化和反序列化的过程,你可以据需要选择,如只接管序列化的过程就用 JsonSerializer ,只接管反序列化的过程就用 JsonDeserializer ,如上面的需求可以用下面的代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

Gsongson=newGsonBuilder()

        .registerTypeAdapter(Integer.class,newJsonDeserializer(){

            @Override

            publicIntegerdeserialize(JsonElementjson,TypetypeOfT,JsonDeserializationContextcontext)throwsJsonParseException{

                try{

                    returnjson.getAsInt();

                }catch(NumberFormatExceptione){

                    return-1;

                }

            }

        })

        .create();

System.out.println(gson.toJson(100));//结果:

100

System.out.println(gson.fromJson("\"\"",Integer.class));//结果-1

下面是所有数字都转成序列化为字符串的例子

1

2

3

4

5

6

7

8

9

10

11

12

13

JsonSerializernumberJsonSerializer=newJsonSerializer(){

    @Override

    publicJsonElementserialize(Numbersrc,TypetypeOfSrc,JsonSerializationContextcontext){

        returnnewJsonPrimitive(String.valueOf(src));

    }

};

Gsongson=newGsonBuilder()

        .registerTypeAdapter(Integer.class,numberJsonSerializer)

        .registerTypeAdapter(Long.class,numberJsonSerializer)

        .registerTypeAdapter(Float.class,numberJsonSerializer)

        .registerTypeAdapter(Double.class,numberJsonSerializer)

        .create();

System.out.println(gson.toJson(100.0f));//结果:

"100.0"

注:

registerTypeAdapter必须使用包装类型,所以int.class,long.class,float.class和double.class是行不通的。

同时不能使用父类来替上面的子类型,这也是为什么要分别注册而不直接使用Number.class的原因。

上面特别说明了registerTypeAdapter不行,那就是有其它方法可行咯?

当然!

换成registerTypeHierarchyAdapter 就可以使用Number.class而不用一个一个的当独注册啦!

registerTypeAdapter与registerTypeHierarchyAdapter的区别:

registerTypeAdapter

registerTypeHierarchyAdapter

支持泛型

支持继承

注:

如果一个被序列化的对象本身就带有泛型,且注册了相应的TypeAdapter,那么必须调用Gson.toJson(Object,Type),明确告诉Gson对象的类型。

1

2

3

4

5

6

7

8

9

10

11

12

Typetype=newTypeToken>(){}.getType();

TypeAdaptertypeAdapter=newTypeAdapter>(){

   //略

};

Gsongson=newGsonBuilder()

        .registerTypeAdapter(type,typeAdapter)

        .create();

Listlist=newArrayList<>();

list.add(newUser("a",11));

list.add(newUser("b",22));

//注意,多了个type参数

Stringresult=gson.toJson(list,type);

三、TypeAdapterFactory

TypeAdapterFactory,见名知意,用于创建TypeAdapter的工厂类,通过对比Type,确定有没有对应的TypeAdapter,没有就返回null,与GsonBuilder.registerTypeAdapterFactory配合使用。

1

2

3

4

5

6

7

8

Gsongson=newGsonBuilder()

    .registerTypeAdapterFactory(newTypeAdapterFactory(){

        @Override

        publicTypeAdaptercreate(Gsongson,TypeTokentype){

            returnnull;

        }

    })

    .create();

四、@JsonAdapter注解

JsonAdapter相较之前介绍的SerializedName、FieldNamingStrategy、Since、Until、Expos这几个注解都是比较特殊的,其它的几个都是用在POJO的字段上,而这一个是用在POJO类上的,接收一个参数,且必须是TypeAdpater,JsonSerializer或JsonDeserializer这三个其中之一。

上面说JsonSerializer和JsonDeserializer都要配合GsonBuilder.registerTypeAdapter使用,但每次使用都要注册也太麻烦了,JsonAdapter就是为了解决这个痛点的。

使用方法(以User为例):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@JsonAdapter(UserTypeAdapter.class)//加在类上

publicclassUser{

    publicUser(){

    }

    publicUser(Stringname,intage){

        this.name=name;

        this.age=age;

    }

    publicUser(Stringname,intage,Stringemail){

        this.name=name;

        this.age=age;

        this.email=email;

    }

    publicStringname;

    publicintage;

    @SerializedName(value="emailAddress")

    publicStringemail;

}

使用时不用再使用 GsonBuilder去注册UserTypeAdapter了。

注:

@JsonAdapter 仅支持 TypeAdapter或TypeAdapterFactory

1

2

3

4

5

Gsongson=newGson();

Useruser=newUser("怪盗kidou",24,"ikidou@");

System.out.println(gson.toJson(user));

//结果:

{"name":

"怪盗kidou","age":

24,"email":

"ikidou@"}

//为区别结果,特意把email字段与@SerializedName注解中设置的不一样

注意:

JsonAdapter的优先级比GsonBuilder.registerTypeAdapter的优先级更高。

五、TypeAdapter与JsonSerializer、JsonDeserializer对比

TypeAdapter

JsonSerializer、JsonDeserializer

引入版本

2.0

1.x

StreamAPI

支持

不支持*,需要提前生成JsonElement

内存占用

比TypeAdapter大

效率

比TypeAdapter低

作用范围

序列化 和 反序列化

序列化 或 反序列化

六、TypeAdapter实例

注:

这里的TypeAdapter泛指TypeAdapter、JsonSerializer和JsonDeserializer。

这里的TypeAdapter上面讲了一个自动将字符串形式的数值转换成int型时可能出现空字符串的问题,下面介绍一个其它读者的需求:

服务器返回的数据中data字段类型不固定,比如请求成功data是一个List,不成功的时候是String类型,这样前端在使用泛型解析的时候,怎么去处理呢?

其实这个问题的原因主要由服务器端造成的,接口设计时没有没有保证数据的一致性,正确的数据返回姿势:

同一个接口任何情况下不得改变返回类型,要么就不要返,要么就返空值,如null、[],{}。

但这里还是给出解决方案:

方案一:

1

2

3

4

5

6

7

8

9

10

11

12

13

Gsongson=newGsonBuilder().registerTypeHierarchyAdapter(List.class,newJsonDeserializer

>>(){

    @Override

    publicList

>deserialize(JsonElementjson,TypetypeOfT,JsonDeserializationContextcontext)throwsJsonParseException{

        if(json.isJsonArray()){

            //这里要自己负责解析了

            GsonnewGson=newGson();

            returnnewGson.fromJson(json,typeOfT);

        }else{

            //和接口类型不符,返回空List

            returnCollections.EMPTY_LIST;

        }

    }

}).create();

方案二:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Gsongson=newGsonBuilder().registerTypeHierarchyAdapter(List.class,newJsonDeserializer

>>(){

    @Override

    publicList

>deserialize(JsonElementjson,TypetypeOfT,JsonDeserializationContextcontext)throwsJsonParseException{

        if(json.isJsonArray()){

            JsonArrayarray=json.getAsJsonArray();

            TypeitemType=((ParameterizedType)typeOfT).getActualTypeArguments()[0];

            Listlist=newArrayList<>();

            for(inti=0;i

                JsonElementelement=array.get(i);

                Objectitem=context.deserialize(element,itemType);

                list.add(item);

            }

            returnlist;

        }else{

            //和接口类型不符,返回空List

            returnCollections.EMPTY_LIST;

        }

    }

}).create();

要注意的点:

∙必须使用registerTypeHierarchyAdapter方法,不然对List的子类无效,但如果POJO中都是使用List,那么可以使用registerTypeAdapter。

∙对于是数组的情况,需要创建一个新的Gson,不可以直接使用context,不然gson又会调我们自定义的JsonDeserializer造成递归调用,方案二没有重新创建Gson,那么就需要提取出List中E的类型,然后分别反序列化

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1