你真的会用Gson吗?Gson使用指南(3)
原文出处: 怪盗kidou
注:此系列基于Gson 2.4。
本次的主要内容:
- 字段过滤的几种方法
- 基于
@Expose注解 - 基于版本
- 基于访问修饰符
- 基于策略(作者最常用)
- 基于
- POJO与JSON的字段映射规则
一、字段过滤的几种方法
字段过滤Gson中比较常用的技巧,特别是在Android中,在处理业务逻辑时可能需要在设置的POJO中加入一些字段,但显然在序列化的过程中是不需要的,并且如果序列化还可能带来一个问题就是 循环引用 ,那么在用Gson序列化之前为不防止这样的事件情发生,你不得不作另外的处理。
以一个商品分类Category 为例。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{ "id": 1, "name": "电脑", "children": [ { "id": 100, "name": "笔记本" }, { "id": 101, "name": "台式机" } ]} |
一个大分类,可以有很多小分类,那么显然我们在设计Category类时Category本身既可以是大分类,也可以是小分类。
|
1
2
3
4
5
|
public class Category { public int id; public String name; public List<Category> children;} |
但是为了处理业务,我们还需要在子分类中保存父分类,最终会变成下面的情况
|
1
2
3
4
5
6
7
|
public class Category { public int id; public String name; public List<Category> children; //因业务需要增加,但并不需要序列化 public Category parent; } |
但是上面的parent字段是因业务需要增加的,那么在序列化是并不需要,所以在序列化时就必须将其排除,那么在Gson中如何排除符合条件的字段呢?下面提供4种方法,大家可根据需要自行选择合适的方式。
基于@Expose注解
@Expose提供了两个属性,且都有默认值,开发者可以根据需要设置不同的值。
@Expose 注解从名字上就可以看出是暴露的意思,所以该注解是用于对处暴露字段的。可是我们以前用Gson的时候也没有@Expose 注解还是不正确的序列化为JSON了么?是的,所以该注解在使用new Gson() 时是不会发生作用。毕竟最常用的API要最简单,所以该注解必须和GsonBuilder配合使用。
使用方法: 简单说来就是需要导出的字段上加上@Expose 注解,不导出的字段不加。注意是不导出的不加。
|
1
2
3
4
5
|
@Expose //@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效@Expose(deserialize = true,serialize = false) //反序列化时生效@Expose(deserialize = false,serialize = true) //序列化时生效@Expose(deserialize = false,serialize = false) // 和不写一样 |
注:根据上面的图片可以得出,所有值为true的属性都是可以不写的。
拿上面的例子来说就是
|
1
2
3
4
5
6
7
8
|
public class Category { @Expose public int id; @Expose public String name; @Expose public List<Category> children; //不需要序列化,所以不加 @Expose 注解, //等价于 @Expose(deserialize = false,serialize = false) public Category parent; } |
在使用Gson时也不能只是简单的new Gson()了。
|
1
2
3
4
|
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create();gson.toJson(category); |
基于版本
Gson在对基于版本的字段导出提供了两个注解 @Since 和 @Until,和GsonBuilder.setVersion(Double)配合使用。@Since 和 @Until都接收一个Double值。
使用方法:当前版本(GsonBuilder中设置的版本) 大于等于Since的值时该字段导出,小于Until的值时该该字段导出。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class SinceUntilSample { @Since(4) public String since; @Until(5) public String until;}public void sineUtilTest(double version){ SinceUntilSample sinceUntilSample = new SinceUntilSample(); sinceUntilSample.since = "since"; sinceUntilSample.until = "until"; Gson gson = new GsonBuilder().setVersion(version).create(); System.out.println(gson.toJson(sinceUntilSample));}//当version <4时,结果:{"until":"until"}//当version >=4 && version <5时,结果:{"since":"since","until":"until"}//当version >=5时,结果:{"since":"since"} |
注:当一个字段被同时注解时,需两者同时满足条件。
基于访问修饰符
什么是修饰符? public、static 、final、private、protected 这些就是,所以这种方式也是比较特殊的。
使用方式:
|
1
2
3
4
5
6
7
8
|
class ModifierSample { final String finalField = "final"; static String staticField = "static"; public String publicField = "public"; protected String protectedField = "protected"; String defaultField = "default"; private String privateField = "private";} |
使用GsonBuilder.excludeFieldsWithModifiers构建gson,支持int形的可变参数,值由java.lang.reflect.Modifier提供,下面的程序排除了privateField 、 finalField 和staticField 三个字段。
|
1
2
3
4
5
6
|
ModifierSample modifierSample = new ModifierSample();Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE) .create();System.out.println(gson.toJson(modifierSample));// 结果:{"publicField":"public","protectedField":"protected","defaultField":"default"} |
到此为止,Gson提供的所有注解就还有一个@JsonAdapter没有介绍了,而@JsonAdapter将和TypeAdapter将作为该系列第4篇也是最后一篇文章的主要内容。
基于策略(自定义规则)
上面介绍的了3种排除字段的方法,说实话我除了@Expose以外,其它的都是只在Demo用上过,用得最多的就是马上要介绍的自定义规则,好处是功能强大、灵活,缺点是相比其它3种方法稍麻烦一点,但也仅仅只是想对其它3种稍麻烦一点而已。
基于策略是利用Gson提供的ExclusionStrategy接口,同样需要使用GsonBuilder,相关API 2个,分别是addSerializationExclusionStrategy 和addDeserializationExclusionStrategy分别针对序列化和反序化时。这里以序列化为例。
例如:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Gson gson = new GsonBuilder() .addSerializationExclusionStrategy(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { // 这里作判断,决定要不要排除该字段,return true为排除 if ("finalField".equals(f.getName())) return true; //按字段名排除 Expose expose = f.getAnnotation(Expose.class); if (expose != null && expose.deserialize() == false) return true; //按注解排除 return false; } @Override public boolean shouldSkipClass(Class<?> clazz) { // 直接排除某个类 ,return true为排除 return (clazz == int.class || clazz == Integer.class); } }) .create(); |
有没有很强大?
二、 POJO与JSON的字段映射规则
之前在你真的会用Gson吗?Gson使用指南(2)属性重命名时 介绍了@SerializedName这个注解的使用,本节的内容与上一次差不多的,但既然叫映射规则那么说的自然是有规律的情况。
还是之前User的例子,已经去除所有注解:
|
1
2
|
User user = new User("怪盗kidou", 24);user.emailAddress = "ikidou@example.com"; |
GsonBuilder提供了FieldNamingStrategy接口和setFieldNamingPolicy和setFieldNamingStrategy 两个方法。
默认实现GsonBuilder.setFieldNamingPolicy 方法与Gson提供的另一个枚举类FieldNamingPolicy配合使用,该枚举类提供了5种实现方式分别为:
| FieldNamingPolicy | 结果(仅输出emailAddress字段) |
|---|---|
| IDENTITY | {“emailAddress”:”ikidou@example.com”} |
| LOWER_CASE_WITH_DASHES | {“email-address”:”ikidou@example.com”} |
| LOWER_CASE_WITH_UNDERSCORES | {“email_address”:”ikidou@example.com”} |
| UPPER_CAMEL_CASE | {“EmailAddress”:”ikidou@example.com”} |
| UPPER_CAMEL_CASE_WITH_SPACES | {“Email Address”:”ikidou@example.com”} |
自定义实现GsonBuilder.setFieldNamingStrategy 方法需要与Gson提供的FieldNamingStrategy接口配合使用,用于实现将POJO的字段与JSON的字段相对应。上面的FieldNamingPolicy实际上也实现了FieldNamingStrategy接口,也就是说FieldNamingPolicy也可以使用setFieldNamingStrategy方法。
用法:
|
1
2
3
4
5
6
7
8
9
|
Gson gson = new GsonBuilder() .setFieldNamingStrategy(new FieldNamingStrategy() { @Override public String translateName(Field f) { //实现自己的规则 return null; } }) .create(); |
注意: @SerializedName注解拥有最高优先级,在加有@SerializedName注解的字段上FieldNamingStrategy不生效!
本文完
本系列:
- 你真的会用Gson吗?Gson使用指南(1)
- 你真的会用Gson吗?Gson使用指南(2)
- 你真的会用Gson吗?Gson使用指南(3)
- from: http://www.importnew.com/23872.html
你真的会用Gson吗?Gson使用指南(3)的更多相关文章
- 你真的会用Gson吗?Gson使用指南(4)
原文出处: 怪盗kidou 注:此系列基于Gson 2.4. 本次文章的主要内容: TypeAdapter JsonSerializer与JsonDeserializer TypeAdapterFac ...
- 你真的会用Gson吗?Gson使用指南(2)
注:此系列基于Gson 2.4. 上一篇文章 你真的会用Gson吗?Gson使用指南(1) 我们了解了Gson的基础用法,这次我们继续深入了解Gson的使用方法. 本次的主要内容: Gson的流式反序 ...
- 你真的会用Gson吗?Gson使用指南
你真的会用Gson吗?Gson使用指南(一) 你真的会用Gson吗?Gson使用指南(二) 你真的会用Gson吗?Gson使用指南(三) 你真的会用Gson吗?Gson使用指南(四)
- 你真的会用Gson吗?Gson使用指南(1)
JSON (官网) 是一种文本形式的数据交换格式,它比XML更轻量.比二进制容易阅读和编写,调式也更加方便.其重要性不言而喻.解析和生成的方式很多,Java中最常用的类库有:JSON-Java.Gso ...
- 让复杂Json数据和对象自由转换 --- Gson
Gson是谷歌用于对Json操作的库,里面有着强大而又方便的功能,最常用的就是 fromJson():将json数据转化为对象: toJson():将对象转化为json数据! 对于普通的json数据使 ...
- 一起来开发Android的天气软件(四)——使用Gson解析数据
离上一篇文章过去才4.5天,我们赶紧趁热打铁继续完毕该系列的天气软件的开发. 承接上一章的内容使用Volley实现网络的通信.返回给我们的是这一串Json数据{"weatherinfo&qu ...
- Gson的学习与使用
Gson介绍: GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串. 特点: a ...
- Gson全解析(中)-TypeAdapter的使用
TypeAdapter介绍 前面的Gson全解析(上)中我们理解并分别运用了JsonSerializer和JsonDeserializer进行JSON和java实体类之间的相互转化.这里利用TypeA ...
- [转]用GSON 五招之内搞定任何JSON数组
关于GSON的入门级使用,这里就不提了,如有需要可以看这篇博文 <Google Gson的使用方法,实现Json结构的相互转换> ,写的很好,通俗易懂. 我为什么写这篇文章呢?因为前几晚跟 ...
随机推荐
- Oracle 数据库、实例、用户、表空间、表之间的关系
数据库: Oracle数据库是数据的物理存储.这就包括(数据文件ORA或者DBF.控制文件.联机日志.参数文件).其实oracle数据库的概念和其它数据库不一样,这里的数据库是一个操作系统只有一个库. ...
- linux java报错汇总
一:♦linux 下javac 编译报 需要class, interface 或enum错误 ♦解析时已到达文件结尾 原因:大括号补匹配 //注意看报警提示
- Java8 容器类详解
ArrayList Vector CopyOnWriteArrayList LinkedList HashMap ConcurrentHashMap LinkedHashMap 使用场景 随机访问 ...
- oracle中游标详细用法
转自:http://blog.csdn.net/liyong199012/article/details/8948952 游标的概念: 游标是SQL的一个内存工作区,由系统或用户以变量的形式定 ...
- ERP退货系统管理(四十五)
添加的存储过程:(添加退货申请信息的存储过程) CREATE PROCEDURE [dbo].[BioBackSendGoods_ADD] @SendBackID INT OUTPUT, ), @Ap ...
- HDU 1029 某个数出现的次数大于等于(N+1)/2的是哪个 map水题
题意:输入n个数 n为奇数 问某个数出现的次数大于等于(N+1)/2的是 哪个 输出来Sample Input51 3 2 3 3111 1 1 1 1 5 5 5 5 5 571 1 1 1 1 1 ...
- struts2之OGNL和struts2标签库和ValueStack对象
OGNL简介: (1)OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目. struts2框架默认就支持Ognl表达式语言(所以 ...
- Codeforces 269C Flawed Flow (看题解)
我好菜啊啊啊.. 循环以下操作 1.从队列中取出一个顶点, 把哪些没有用过的边全部用当前方向. 2.看有没有点的入度和 == 出度和, 如果有将当前的点加入队列. 现在有一个问题就是, 有没有可能队列 ...
- BZOJ1191 [HNOI2006]超级英雄Hero 二分图匹配
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1191 题目概括 有m个题目,有n个解决方案:对于每一个题目,有两种解决方案可用. 每种解决方案只能 ...
- 6-20 Ideal Path uva1599
第一个bfs很快 但是我第一次做还用了结构体 这题完全不需要 反而导致了代码非常乱 输入: 一开始我是用m二维数组储存颜色 vector path来储存路径 但是二维数组的下标是不够用的 ...