You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Moshi解析Kotlin Unit类型 解决Retrofit BaseResponse<Unit>转换报错

问题根因

你自定义的UnitConverterFactory仅匹配接口直接返回Unit的场景,当前接口返回的是泛型包装类BaseResponse<Unit>,原有判断逻辑无法命中,Moshi在尝试为BaseResponse<Unit>生成解析器时,无法识别Unit类型的泛型参数,因此抛出无法创建转换器的异常。


解决方案

推荐两种可行的配置方式,任选其一即可:

方案一:为Moshi添加Unit类型适配器(更简洁)

让Moshi原生支持解析Unit类型的字段,无需修改原有接口定义:

  1. 定义Unit的Json适配器:
object UnitAdapter {
    @ToJson
    fun toJson(unit: Unit): Any = ""

    @FromJson
    fun fromJson(reader: JsonReader): Unit {
        // 直接跳过data字段的解析,返回Unit实例
        reader.skipValue()
        return Unit
    }
}
  1. 初始化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>类型的响应:

  1. 定义自定义转换器工厂:
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
                }
            }
        }
    }
}
  1. 初始化Retrofit时,将该转换器工厂放在MoshiConverterFactory前面注册,保证优先命中:
val retrofit = Retrofit.Builder()
    .baseUrl(你的服务地址)
    .addConverterFactory(BaseResponseUnitConverterFactory) // 放在Moshi转换器前面
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    // 其他配置
    .build()

注意事项

无论选择哪种方案,都要保证Moshi初始化时添加了KotlinJsonAdapterFactory,否则Kotlin类的默认值、空值处理都可能出现异常。

内容的提问来源于stack exchange,提问作者Haocun Ni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:36:04