如何用Moshi解析Kotlin Unit类型 解决Retrofit BaseResponse<Unit>转换报错
问题根因
你自定义的UnitConverterFactory仅匹配接口直接返回Unit的场景,当前接口返回的是泛型包装类BaseResponse<Unit>,原有判断逻辑无法命中,Moshi在尝试为BaseResponse<Unit>生成解析器时,无法识别Unit类型的泛型参数,因此抛出无法创建转换器的异常。
解决方案
推荐两种可行的配置方式,任选其一即可:
方案一:为Moshi添加Unit类型适配器(更简洁)
让Moshi原生支持解析Unit类型的字段,无需修改原有接口定义:
- 定义Unit的Json适配器:
object UnitAdapter { @ToJson fun toJson(unit: Unit): Any = "" @FromJson fun fromJson(reader: JsonReader): Unit { // 直接跳过data字段的解析,返回Unit实例 reader.skipValue() return Unit } }
- 初始化Moshi时注册该适配器:
// 需提前引入moshi-kotlin依赖,保证Kotlin类解析正常 // implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(UnitAdapter) // 其他自定义适配器按顺序添加即可 .build() // 传给MoshiConverterFactory val retrofit = Retrofit.Builder() .baseUrl(你的服务地址) .addConverterFactory(MoshiConverterFactory.create(moshi)) // 其他配置 .build()
原有自定义的UnitConverterFactory可以直接移除,该方案适配所有BaseResponse<Unit>类型的接口。
方案二:自定义适配BaseResponse<Unit>的Converter.Factory
如果不想全局修改Moshi配置,可以单独处理BaseResponse<Unit>类型的响应:
- 定义自定义转换器工厂:
object BaseResponseUnitConverterFactory : Converter.Factory() { override fun responseBodyConverter( type: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): Converter<ResponseBody, *>? { // 校验类型是否为BaseResponse<Unit> if (type !is ParameterizedType) return null if (type.rawType != BaseResponse::class.java) return null val genericArg = type.actualTypeArguments.firstOrNull() ?: return null if (genericArg != Unit::class.java) return null // 命中后返回对应转换器 return Converter<ResponseBody, BaseResponse<Unit>> { body -> body.use { responseBody -> // 复用Moshi解析基础字段,忽略data解析 val tempType = Types.newParameterizedType(BaseResponse::class.java, Any::class.java) val converter = retrofit.nextResponseBodyConverter<BaseResponse<Any>>( this, tempType, annotations ) val tempResp = converter.convert(responseBody) BaseResponse<Unit>().apply { code = tempResp?.code message = tempResp?.message data = Unit } } } } }
- 初始化Retrofit时,将该转换器工厂放在
MoshiConverterFactory前面注册,保证优先命中:
val retrofit = Retrofit.Builder() .baseUrl(你的服务地址) .addConverterFactory(BaseResponseUnitConverterFactory) // 放在Moshi转换器前面 .addConverterFactory(MoshiConverterFactory.create(moshi)) // 其他配置 .build()
注意事项
无论选择哪种方案,都要保证Moshi初始化时添加了KotlinJsonAdapterFactory,否则Kotlin类的默认值、空值处理都可能出现异常。
内容的提问来源于stack exchange,提问作者Haocun Ni
相关产品推荐
相关产品推荐

