原文出处: 怪盗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

@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值。

Since和Until注解

使用方法:当前版本(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"}

注:当一个字段被同时注解时,需两者同时满足条件。

基于访问修饰符

什么是修饰符? publicstatic 、finalprivateprotected 这些就是,所以这种方式也是比较特殊的。
使用方式:

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接口和setFieldNamingPolicysetFieldNamingStrategy 两个方法。

默认实现
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使用指南(3)的更多相关文章

  1. 你真的会用Gson吗?Gson使用指南(4)

    原文出处: 怪盗kidou 注:此系列基于Gson 2.4. 本次文章的主要内容: TypeAdapter JsonSerializer与JsonDeserializer TypeAdapterFac ...

  2. 你真的会用Gson吗?Gson使用指南(2)

    注:此系列基于Gson 2.4. 上一篇文章 你真的会用Gson吗?Gson使用指南(1) 我们了解了Gson的基础用法,这次我们继续深入了解Gson的使用方法. 本次的主要内容: Gson的流式反序 ...

  3. 你真的会用Gson吗?Gson使用指南

    你真的会用Gson吗?Gson使用指南(一) 你真的会用Gson吗?Gson使用指南(二) 你真的会用Gson吗?Gson使用指南(三) 你真的会用Gson吗?Gson使用指南(四)

  4. 你真的会用Gson吗?Gson使用指南(1)

    JSON (官网) 是一种文本形式的数据交换格式,它比XML更轻量.比二进制容易阅读和编写,调式也更加方便.其重要性不言而喻.解析和生成的方式很多,Java中最常用的类库有:JSON-Java.Gso ...

  5. 让复杂Json数据和对象自由转换 --- Gson

    Gson是谷歌用于对Json操作的库,里面有着强大而又方便的功能,最常用的就是 fromJson():将json数据转化为对象: toJson():将对象转化为json数据! 对于普通的json数据使 ...

  6. 一起来开发Android的天气软件(四)——使用Gson解析数据

    离上一篇文章过去才4.5天,我们赶紧趁热打铁继续完毕该系列的天气软件的开发. 承接上一章的内容使用Volley实现网络的通信.返回给我们的是这一串Json数据{"weatherinfo&qu ...

  7. Gson的学习与使用

    Gson介绍: GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串. 特点: a ...

  8. Gson全解析(中)-TypeAdapter的使用

    TypeAdapter介绍 前面的Gson全解析(上)中我们理解并分别运用了JsonSerializer和JsonDeserializer进行JSON和java实体类之间的相互转化.这里利用TypeA ...

  9. [转]用GSON 五招之内搞定任何JSON数组

    关于GSON的入门级使用,这里就不提了,如有需要可以看这篇博文 <Google Gson的使用方法,实现Json结构的相互转换> ,写的很好,通俗易懂. 我为什么写这篇文章呢?因为前几晚跟 ...

随机推荐

  1. node基础知识

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,是一个可以让 JavaScript 运行在服务器端的平台 Node.js 使用了一个事件驱动.非阻塞式 I/O ...

  2. [转]安装ambari

    一.准备工作: 基本工具 yumrpmscpcurlwgetpdsh前几个一般系统都自带了,pdsh需要自己装 yum install pdsh 2.配置hosts vim /etc/hosts 10 ...

  3. Deep Learning系统实训之三:卷积神经网络

    边界填充(padding):卷积过程中,越靠近图片中间位置的像素点越容易被卷积计算多次,越靠近边缘的像素点被卷积计算的次数越少,填充就是为了使原来边缘像素点的位置变得相对靠近中部,而我们又不想让填充的 ...

  4. git提交本地分支到远程分支

    git提交本地分支到远程分支   git 常用命令(含删除文件) Git常用操作命令收集: 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/j ...

  5. 接口隔离原则(Interface Segregation Principle, ISP)

    使用多个专门的接口,而不使用单一的总接口 接口隔离有两种定义: Clients should not be forced to depend upon interfaces that they don ...

  6. BZOJ3064 Tyvj 1518 CPU监控 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3064 题意概括 一个序列,要你支持以下操作: 1. 区间询问最大值 2. 区间询问历史最大值 3. ...

  7. C++语言实现-邻接表

    图的邻接表实现 邻接表是图的一种链式存储结构.主要是应对于邻接矩阵在顶点多边少的时候,浪费空间的问题.它的方法就是声明两个结构.如下图所示: 先来看看伪代码: typedef char Vertext ...

  8. 使用tortoisegit简化命令

    1. 如果希望git保存用户名和密码,后续操作都无需输入密码: git命令: git config --global credential.helper store   或者通过tortoisegit ...

  9. grant 权限 on 数据库对象 to 用户

    grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删除 数据库中所有表数据的权利. grant select on testdb.* to common_ ...

  10. FTP 其他设置

    参考文章 http://faichen.vip.blog.163.com/blog/static/37644066201010362051291/