kotlin reified关键字优化gson TypeToken解析函数

2,751 阅读1分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

简单的记录。

我们在使用gson时,常常需要使用TypeToken解析泛型嵌套的数据,然后将重复代码提取成函数。

实体类:

class Entity<T> {
    var type: Int = 0
    var data: T? = null
}

将typeToken中的泛型提出:

fun <T> convertJson(json: String): T? {
   return try {
       val typeToken =
           object: TypeToken<Entity<T>>(){}.type
       Gson().fromJson<Entity<T>>(json, typeToken).data
  } catch (e: java.lang.Exception) {
       null
  }
}

但实际运行解析报错:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to XXX

原因是在TypeToken使用泛型时,泛型需要是确定的类型。改为使用TypeToken.getParameterized()函数获取type对象。

fun <T> convertJson(json: String, t: Class<T>): T? {
   return try {
       val typeToken =
           TypeToken.getParameterized(Entity::class.java, t).type
       Gson().fromJson<Entity<T>>(json, typeToken).data
  } catch (e: java.lang.Exception) {
       null
  }
}

使用TypeToken.getParameterized()可解决gson解析异常的问题。函数需要多传一个参数,T的class对象。

这时我们可以使用reified关键字对函数进行精简:

inline fun <reified T> convertJson(json: String): T? {
    return try {
        val typeToken =
            TypeToken.getParameterized(Entity::class.java, T::class.java).type
        Gson().fromJson<Entity<T>>(json, typeToken).data
    } catch (e: java.lang.Exception) {
        null
    }
}

其中reified关键字和inline关键字都是不能省略的,省略reified,AndroidStudio提示:

Cannot use 'T' as reified type parameter. Use a class instead.

省略inline,提示:

Only type parameters of inline functions can be reified.

因为是内联函数,函数体不宜过长,逻辑不易太复杂。

不当之处欢迎指正。