使用Moshi反序列化泛型响应 处理data字段为不同类型的服务端返回结果
Moshi完全支持该泛型适配需求,推荐使用自定义JsonAdapter.Factory的方案实现,无性能开销且无需修改原有接口定义:
步骤1:调整基础响应模型的可空性
原有非空data字段在错误响应为空对象时会直接触发解析异常,先修改为可空类型:
data class BaseResponseResult<T>( @Json(name = "data") val data: T?, // 修改为可空 @Json(name = "success") val success: Boolean, @Json(name = "errors") val errors: List<Error> )
步骤2:实现泛型适配的JsonAdapter工厂
通过工厂动态获取对应接口的data泛型类型解析器,同时统一处理错误抛出逻辑,适配RxJava的错误回调机制:
import com.squareup.moshi.* import com.squareup.moshi.internal.Util import java.lang.reflect.ParameterizedType import java.lang.reflect.Type class BaseResponseJsonAdapterFactory : JsonAdapter.Factory { override fun create( type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi ): JsonAdapter<*>? { // 仅处理BaseResponse类型的反序列化 if (Types.getRawType(type) != BaseResponse::class.java) return null // 提取BaseResponse的泛型参数(即对应接口的data类型) val dataType = Types.getParameterUpperBound(0, (type as ParameterizedType).actualTypeArguments[0]) val dataAdapter = moshi.adapter<Any>(dataType) val resultType = Types.newParameterizedType(BaseResponseResult::class.java, dataType) val resultAdapter = moshi.adapter<BaseResponseResult<Any>>(resultType) val stringAdapter = moshi.adapter(String::class.java) val nullableStringAdapter = stringAdapter.nullSafe() return object : JsonAdapter<BaseResponse<Any>>() { override fun fromJson(reader: JsonReader): BaseResponse<Any> { reader.beginObject() var jsonrpc = "" var id: String? = null var result: BaseResponseResult<Any>? = null while (reader.hasNext()) { when (reader.nextName()) { "jsonrpc" -> jsonrpc = stringAdapter.fromJson(reader) ?: "" "id" -> id = nullableStringAdapter.fromJson(reader) "result" -> result = resultAdapter.fromJson(reader) else -> reader.skipValue() } } reader.endObject() val finalResult = result ?: throw JsonDataException("响应缺失result字段") // 错误响应直接抛业务异常,RxJava自动进入onError回调 if (!finalResult.success) { val error = finalResult.errors.firstOrNull() throw BusinessException( code = error?.code ?: -1, errorMsg = error?.message ?: "未知业务错误" ) } // 成功响应校验data非空 val finalData = finalResult.data ?: throw JsonDataException("成功响应缺失data字段") return BaseResponse(jsonrpc, id, finalResult) } override fun toJson(writer: JsonWriter, value: BaseResponse<Any>?) { // 仅用于响应解析无需序列化,空实现即可 } } } } // 自定义业务异常,统一在RxJava的onError中处理 class BusinessException(val code: Int, val errorMsg: String) : Exception(errorMsg)
步骤3:注册工厂到Moshi实例
初始化Moshi时将自定义工厂放在最前面注册即可,原有Retrofit接口、业务响应类无需任何修改:
val moshi = Moshi.Builder() .add(BaseResponseJsonAdapterFactory()) .add(KotlinJsonAdapterFactory()) // 配合Kotlin数据类使用必须添加 .build() // 后续将该Moshi实例配置给Retrofit的MoshiConverterFactory即可
方案适配效果
- 请求成功时自动将data解析为对应接口定义的实体类型(如
LoginResponse、ProfileResponse) - 请求失败时自动抛出业务异常,无需在每个接口回调中重复判断
success字段 - 支持任意泛型类型的data字段扩展,新增接口无需额外修改适配逻辑
内容的提问来源于stack exchange,提问作者allo86
相关产品推荐
相关产品推荐

