Gson Advanced — 简单自定义序列化 (Part 1)

本文介绍了如何使用Gson进行自定义序列化,以减少数据传输量。通过@Expose注解简化对象输出,然后通过GsonBuilder注册自定义Serializer,实现了对单个对象和List对象的简化序列化,从而提高效率。同时讨论了自定义序列化过程中需要注意的问题,并给出了优化JSON格式的目标。
摘要由CSDN通过智能技术生成

原文链接:[Gson Advanced — Custom Serialization for Simplification (Part 1)](https://futurestud.io/tutorials/gson-advanced-custom-serialization-part-1
)
原文出自:Norman Peitek
译者:無名無

本文将实现一个自定义的 Gson serialization 过程,有些情况我们可能会考虑到自定义,例如:和 server 通信时,有时候不需要传递一个完成 JSON 信息,只需要关键信息即可,接下来我们一步一步分析。

自定义序列化

有个这样的场景:App 从 服务器获取一个列表,用户可以订阅列表中的每一项,但是要将订阅的某一条发送给服务器同步。
我们一步一步实现:

Models

public class UserSimple {  
    private String name;
    private String email;
    private boolean isDeveloper;
    private int age;
}

public class Merchant {  
    private int Id;
    private String name;

    // possibly more properties
}

用于解析完整列表的 Model:

public class UserSubscription {  
    String name;
    String email;
    int age;
    boolean isDeveloper;

    // new!
    List<Merchant> merchantList;
}

问题

先看输出:

{
  "age": 26,
  "email": "norman@fs.io",
  "isDeveloper": true,
  "merchantList": [
    {
      "Id": 23,
      "name": "Future Studio"
    },
    {
      "Id": 42,
      "name": "Coffee Shop"
    }
  ],
  "name": "Norman"
}

这是一个非常标准 JSON 的输出,但是在实际中,不可能是这么小的数据量,而且 Merchant 结构可能非常复杂,这就会造成 JSON 数据非常大,从而导致解析或传递耗时。

使用 @Expose 简化

我们第一个想到的方法是减少 Merchant 中不必要字段的序列化,使用之前学过的 @Expose 来简化 JSON,我们来调整下 Merchant:

public class Merchant {  
    private int Id;

    @Expose(serialize = false)
    private String name;

    // possibly more properties
}

再来看输出:

  {
    "age": 26,
    "email": "norman@fs.io",
    "isDeveloper": true,
    "merchantList": [
      {
        "Id": 23
      },
      {
        "Id": 42
      }
    ],
    "name": "Norman"
  }

从结果上看已经减少输出了 name 字段,看起来已经优化了,但是问题又来了,如果其他接口,需要一个完整的 JSON 结果,这该怎么办?接着往下看。

简化自定义序列化为单个对象

通过 @Expose 是能解决一部分问题,但是存在局限性,现在我们使用自定义来解决这些问题,作法不干涉 Merchant 类,只在干涉序列化过程。

先看一个最原始的例子:

// get the list of merchants from an API endpoint
Merchant futureStudio = new Merchant(23, "Future Studio", null);  
Merchant coffeeShop = new Merchant(42, "Coffee Shop", null);

// create a new subscription object and pass the merchants to it
List<Merchant> subscribedMerchants = Arrays.asList(futureStudio, coffeeShop);  
UserSubscription subscription = new UserSubscription(  
        "Norman",
        "norman@fs.io",
        26,
        true,
        subscribedMerchants);

Gson gson = new Gson();  
String fullJSON = gson.toJson(subscription); 

为了实现自定义需求,我们需要使用 GsonBuilder 来帮我们生成 Gson 实例,需要给 Merchant 类注册一个 adapter,大概是这种:

GsonBuilder gsonBuilder = new GsonBuilder();

JsonSerializer<Merchant> serializer = ...; // will implement in a second  
gsonBuilder.registerTypeAdapter(Merchant.class, serializer);

Gson customGson = gsonBuilder.create();  
String customJSON = customGson.toJson(subscription);

大部分都还是之前介绍过的方法,唯一陌生的是 registerTypeAdapter() 方法,需要传入两个参数,第一个序列化对象类型,第二个是 JsonSerializer 接口的具体实现。

来看一个 JsonSerializer 实现实例:

JsonSerializer<Merchant> serializer = new JsonSerializer<Merchant>() {  
    @Override
    public JsonElement serialize(Merchant src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jsonMerchant = new JsonObject();

        jsonMerchant.addProperty("Id", src.getId());

        return jsonMerchant;
    }
};

JsonSerializer 实现只有一个 serialize 方法,我们重写次方法,在方法内添加我们处理,这里使用 JsonObject 只添加 src 的 id 字段。

根据自己的需求选择调用响应的方法,再次输出:

  "age": 26,
  "email": "norman@fs.io",
  "isDeveloper": true,
  "merchantList": [
    {
      "Id": 23
    },
    {
      "Id": 42
    }
  ],
  "name": "Norman"
}

可以看到上面的结果和使用 @Expose 的结果是一样的,下一节我们通过自定义序列化 List 来简化 JSON。

简化自定义序列化 List 对象

和自定义序列化对象类似,我们只需要更改下 JsonSerializer 中的类型为 List 即可,类似这样:

GsonBuilder gsonBuilder = new GsonBuilder();

Type merchantListType = new TypeToken<List<Merchant>>() {}.getType();  
JsonSerializer<List<Merchant>> serializer = ...; // will implement in a second  
gsonBuilder.registerTypeAdapter(merchantListType, serializer);

Gson customGson = gsonBuilder.create();  
String customJSON = customGson.toJson(subscription);  

同样具体的实现如下:

JsonSerializer<List<Merchant>> serializer =  
    new JsonSerializer<List<Merchant>>() {
        @Override
        public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
            JsonObject jsonMerchant = new JsonObject();

            List<String> merchantIds = new ArrayList<>(src.size());
            for (Merchant merchant : src) {
                merchantIds.add("" + merchant.getId());
            }

            String merchantIdsAsString = TextUtils.join(",", merchantIds);

            jsonMerchant.addProperty("Ids", merchantIdsAsString);

            return jsonMerchant;
        }
}

同样看下输出结果:

{
  "age": 26,
  "email": "norman@fs.io",
  "isDeveloper": true,
  "merchantList": {
    "Ids": "23,42"
  },
  "name": "Norman"
}

我们可以看到,merchantList 中,大大减少了输出,这对于客户端和服务器都是有利的,有利于提升访问速度和性能。但是 merchantList 中的数据格式有些问题,我们下一节来调整下。

简化自定义序列化 List 为数组

针对上一节的问题,我们只需要修改 serialize方法中的实现即可,不在使用 JsonObject,而是使用 JsonArray,实现如下:

JsonSerializer<List<Merchant>> serializer =  
    new JsonSerializer<List<Merchant>>() {
        @Override
        public JsonElement serialize(List<Merchant> src, Type typeOfSrc, JsonSerializationContext context) {
            JsonArray jsonMerchant = new JsonArray();

            for (Merchant merchant : src) {
                jsonMerchant.add("" + merchant.getId());
            }

            return jsonMerchant;
        }
}

最终的结果:

{
  "age": 26,
  "email": "norman@fs.io",
  "isDeveloper": true,
  "merchantList": [
    "23",
    "42"
  ],
  "name": "Norman"
}

在上面的三个 case 中,我们看到可以看简单的使用 Gson 的自定义序列化,具体逻辑部分需要我们自己实现。

一些问题

1、多次使用 registerTypeAdapter() 以最后一次为准。
2、注意方法内部不要造成无限循环,例如:

new JsonSerializer<UserSubscription>() {  
    @Override
    public JsonElement serialize(UserSubscription src, Type typeOfSrc, JsonSerializationContext context) {
        JsonElement jsonSubscription = context.serialize(src, typeOfSrc);

        // customize jsonSubscription here

        return jsonSubscription;
    }
}

目标

了解 Gson 自定义序列化几种方式,来优化 JSON 传递的数据量大小,下一篇将继续讨论自定义问题。

练习代码已上传 Github https://github.com/whiskeyfei/Gson-Review 可自行查看。

Gson 系列文章翻译回顾

1、Gson - Java-JSON 序列化和反序列化入门
2、Gson - 映射嵌套对象
3、Gson - Arrays 和 Lists 映射对象
4、Gson - Map 结构映射
5、Gson - Set 集合映射
6、Gson - 空值映射
7、Gson Model Annotations - 如何使用 @SerializedName 更改字段的命名
8、Gson Model Annotations - @SerializedName 匹配多个反序列化名称
9、Gson Builder - 基础和命名规则
10、Gson Builder - 序列化空值
11、Gson Builder - 忽略策略
12、Gson Builder - Gson Lenient 属性
13、Gson Builder - 特殊类型 Floats & Doubles
17、Gson Builder - 如何使用 @Expose 忽略字段
19、Gson Advanced - 映射枚举类型
20、Gson Advanced - 映射循环引用
21、Gson Advanced - 泛型
22、Gson Advanced - 简单自定义序列化 (Part 1)
24、Gson Advanced - 自定义反序列化基础
25、Gson Advanced - 自定义对象实例创建
26、Gson Advanced - 通过 @JsonAdapter 自定义(反)序列化过程
32、Practical Gson - 如何解析多态对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值