Gson枚举序列化实现

众所周知,Json是无法传递枚举类型的,在对Json处理的过程中,可能大家或多或少都会遇到对于枚举处理的问题,当然解决方式也有很多种,本篇仅针对使用Gson处理Json时对于枚举问题给出一种解决方式,可能并不能适用于小伙伴们实际应用的所有场景,但作为借鉴也算是一个不错的选择。

Gson简介

Gson是Google提供的一个Java库,用于将Java对象转换成Json字符串,以及将Json字符串转换成Java对象。它在Android开发中被广泛使用。

主要特点

  • 简单易用: Gson提供了简单的方法来实现Java对象与Json字符串之间的转换,无需编写复杂的代码。
  • 支持复杂类型: 能够处理Java中的各种复杂类型,包括集合、泛型等。
  • 自定义序列化和反序列化: 通过TypeAdapter和TypeAdapterFactory等机制,可以自定义序列化和反序列化的过程,满足特定的需求。
  • 注解支持: 提供了如@SerializedName、@Expose等注解,方便控制字段的序列化和反序列化行为。

Gson的具体用法本篇就不再过多赘述,有需要的可以参考GsonUtils

枚举序列化实现原理

实现将会使用上面简介中提到的TypeAdapter和TypeAdapterFactory两个用于自定义序列化和反序列化过程的重要组件。

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

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

我们将通过TypeAdapter和TypeAdapterFactory仅对枚举类型进行序列化和反序列化的操作,因为枚举本身不支持序列化,因此我们需要将其转换成可以进行序列化的类型,而本篇会给出将枚举转为Int和String的实现,至于其他的可序列化类型,相信通过本篇的了解,自行实现也是非常简单的。

编码实现

枚举序列化前的数据准备

根据我们上面实现描述,我们需要将枚举转化为可以进行序列化的类型,那么我们需要有一个类来描述可以序列化为什么类型,让我们新建一个枚举类EnumMappingType,并添加如下代码:

enum class EnumMappingType {
   
   
    INT,
    STRING,
    LONG,
    DOUBLE,
    BOOLEAN;
}

接着就是我们本次实现的核心代码,通过继承TypeAdapter实现枚举序列化和反序列化的核心逻辑,让我们继续新增一个类EnumTypeAdapter:

class EnumTypeAdapter<T: Any>(type: TypeToken<T>): TypeAdapter<T>(){
   
   

    override fun write(out: JsonWriter?, value: T) {
   
   
        TODO("Not yet implemented")
    }

    override fun read(`in`: JsonReader?): T {
   
   
        TODO("Not yet implemented")
    }
}

该类我们继承自TypeAdapter,并且仅存在一个参数为TypeToken<T>的构造函数,这里的TypeToken可以理解为我们需要处理的枚举类型在Gson中的封装对象,处理时会通过Gson传入并调用write和read进行序列化和反序列化操作。接着让我们来继续完善它。

    //枚举元素与序列化数据之间的映射表
    private var maps = mutableMapOf<T, EnumValue>()

    //枚举值与类型的封装
    private data class EnumValue(var value: Any, var type: EnumMappingType)

    init {
        //遍历枚举类中所有的枚举元素
        type.rawType.enumConstants.filterNotNull().forEach {
            val tt: T = it as T

            //通过反射获取每个元素的ordinal,以枚举元素为键,将ordinal返回值和EnumMappingType.INT类型进行封装为EnumValue作为值存储至maps
            val ordinal = tt.javaClass.superclass.getDeclaredMethod("ordinal")
            var accessible = ordinal.isAccessible
            ordinal.isAccessible = true
            maps[tt] = EnumValue(ordinal.invoke(it) as Int, EnumMappingType.INT)
            ordinal.isAccessible = accessible
        }
    }

添加了一个MutableMap类型的全局变量maps,这个maps用来保存枚举与对应序列化数据的映射关系。

EnumValue类用于保存枚举转为序列化数据的值和类型。

而init代码块则是会在序列化和反序列化之前准备的枚举的映射数据,每个需要进行序列化的枚举类会先通过init代码块遍历所有枚举类的元素,并将他们根据一定的规则进行序列化数据映射,我们这里是将枚举映射为了int值,而这个int值则是枚举的序号ordinal。

初始化数据完成之后,接着让我们开始着手序列化和反序列化的操作,首先先进行序列化操作。

枚举序列化

    override fun write(writer: JsonWriter, value: T) {
   
   
        if (value == null) {
   
   
            writer.nullValue()
        } else {
   
   
            val valueType = maps[value]!!
            when (valueType.type) {
   
   
                EnumMappingType.INT -> writer.value(valueType.value as Int)
                EnumMappingType.STRING -> writer.value
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值