如何在Kotlin Android中为嵌套数据类自定义Retrofit转换器工厂
问题:Retrofit嵌套字段类型转换与方案选择
我的模型类为StudentResponse,现有自定义Retrofit Converter Factory代码如下:
class BaseConverterFactory private constructor() : Converter.Factory() { override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? { LogUtils.d("Hello type: " + type) if (type === String::class.java) { return Converter { value -> value.string() } } else if (type === Int::class.java) { return Converter { value -> Integer.valueOf(value.string()) } } else if (type === Double::class.java) { return Converter { value -> java.lang.Double.valueOf(value.string()) } } else if (type === Boolean::class.java) { return Converter { value -> java.lang.Boolean.valueOf(value.string()) } } return null } companion object { fun create(): BaseConverterFactory { return BaseConverterFactory() } } }
对应的实体类代码:
data class StudentResponse( var aggregatedValues: List<Books>?, ) data class Books( var bookValue: Double?, // 需要将接口返回的Double值(如34.11)取整为Int存入该字段 )
当前Converter仅能处理基础类型的直接转换,无法处理StudentResponse嵌套结构中Books类的bookValue字段类型转换需求。另外,针对全项目频繁出现的这类类型转换场景,选择Retrofit Converter Factory还是Gson反序列化方案更合适?
解答
一、实现嵌套字段的类型转换
方案1:基于Gson自定义TypeAdapter
这是处理嵌套字段转换更直接的方式,针对特定字段或类定制反序列化规则:
- 为
Books类编写自定义TypeAdapter:
class BooksTypeAdapter : TypeAdapter<Books>() { override fun write(out: JsonWriter, value: Books?) { // 序列化逻辑按需实现,此处仅处理反序列化 out.beginObject() value?.bookValue?.let { out.name("bookValue").value(it.toInt()) } ?: out.name("bookValue").nullValue() out.endObject() } override fun read(`in`: JsonReader): Books { var bookValue: Double? = null `in`.beginObject() while (`in`.hasNext()) { when (`in`.nextName()) { "bookValue" -> { // 读取Double值后取整,再转为Double类型赋值(若字段可改为Int则直接转Int) val doubleValue = `in`.nextDouble() bookValue = doubleValue.toInt().toDouble() } else -> `in`.skipValue() // 跳过其他未处理字段 } } `in`.endObject() return Books(bookValue) } }
- 在Gson实例中注册适配器并配置到Retrofit:
val gson = GsonBuilder() .registerTypeAdapter(Books::class.java, BooksTypeAdapter()) .create() val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build()
方案2:扩展Retrofit Converter Factory
若坚持使用自定义Converter Factory,需结合Gson解析复杂对象,而非仅处理基础类型:
class CustomConverterFactory private constructor(private val gson: Gson) : Converter.Factory() { override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *> { val delegate = gson.getAdapter(TypeToken.get(type)) as TypeAdapter<Any> return Converter { body -> val json = body.string() val jsonElement = JsonParser.parseString(json) // 针对StudentResponse的嵌套字段做修改 if (type === StudentResponse::class.java) { jsonElement.asJsonObject.getAsJsonArray("aggregatedValues")?.forEach { bookJson -> val bookObj = bookJson.asJsonObject if (bookObj.has("bookValue")) { val doubleValue = bookObj.get("bookValue").asDouble bookObj.addProperty("bookValue", doubleValue.toInt().toDouble()) } } } delegate.fromJson(jsonElement.toString()) } } companion object { fun create(): CustomConverterFactory { val gson = GsonBuilder().create() return CustomConverterFactory(gson) } } }
这种方式需手动遍历JSON结构,代码复杂度高,仅适合全局少量规则的场景。
二、方案对比与选择
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Gson TypeAdapter | 1. 针对特定类/字段定制规则,精准度高 2. 代码模块化,易维护 3. 性能优于全局Converter | 需为每个转换类编写适配器,多场景下代码量稍大 | 项目中存在多个分散的字段/类转换需求 |
| Retrofit Converter Factory | 1. 可全局统一处理所有请求响应 2. 无需修改实体类结构(部分场景) | 1. 处理嵌套结构时需手动解析JSON,代码繁琐易出错 2. 全局规则灵活性低 | 单一全局转换规则的场景 |
结论:针对全项目频繁出现的类型转换需求,优先选择Gson自定义TypeAdapter方案。它更符合单一职责原则,代码可维护性更高,且能精准处理不同类的不同转换规则,避免全局Converter带来的复杂度。
内容的提问来源于stack exchange,提问作者Ishika Singh
相关产品推荐
相关产品推荐

