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

如何让Retrofit内部用BaseResponseDto包装响应并转为ApiResult?

实现Retrofit自动转换BaseResponseDto到ApiResult的方案

要实现Retrofit内部自动将接口响应包装为BaseResponseDto<T>并转换为ApiResult<T>,无需在API接口中显式声明BaseResponseDto,需要自定义Call Adapter Factory,具体步骤如下:

1. 实现自定义CallAdapter.Factory

这个工厂类负责识别接口中返回ApiResult<T>的挂起函数,自动将实际响应类型替换为BaseResponseDto<T>,并创建对应的转换适配器。

import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Retrofit
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

class ApiResultCallAdapterFactory : CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<out Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {
        // 仅处理返回ApiResult<T>的挂起函数
        val rawReturnType = CallAdapter.Factory.getRawType(returnType)
        if (rawReturnType != kotlin.coroutines.Continuation::class.java) {
            return null
        }

        // 提取ApiResult的泛型参数T(如LoginResponseDto)
        val apiResultGenericType = CallAdapter.Factory.getParameterUpperBound(0, returnType as ParameterizedType)
        // 构建BaseResponseDto<T>的参数化类型
        val baseResponseType = object : ParameterizedType {
            override fun getRawType(): Type = BaseResponseDto::class.java
            override fun getActualTypeArguments(): Array<Type> = arrayOf(apiResultGenericType)
            override fun getOwnerType(): Type? = null
        }

        // 获取Retrofit默认的协程适配器,用于处理BaseResponseDto<T>
        val delegateAdapter = retrofit.nextCallAdapter(this, baseResponseType, annotations)
        return ApiResultCallAdapter(delegateAdapter)
    }
}

2. 实现ApiResultCallAdapter

这个类负责将BaseResponseDto<T>转换为ApiResult<T>,处理业务成功、业务失败、HTTP错误、网络异常等多种场景,同时完成List<Int>到List<Error>的类型映射。

import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Callback
import retrofit2.Response
import java.lang.reflect.Type

class ApiResultCallAdapter<T>(
    private val delegate: CallAdapter<T, *>
) : CallAdapter<T, Call<ApiResult<T>>> {
    override fun responseType(): Type = delegate.responseType()

    override fun adapt(call: Call<T>): Call<ApiResult<T>> {
        val baseResponseCall = delegate.adapt(call) as Call<BaseResponseDto<T>>
        return object : Call<ApiResult<T>> {
            override fun enqueue(callback: Callback<ApiResult<T>>) {
                baseResponseCall.enqueue(object : Callback<BaseResponseDto<T>> {
                    override fun onResponse(
                        call: Call<BaseResponseDto<T>>,
                        response: Response<BaseResponseDto<T>>
                    ) {
                        val baseResponse = response.body()
                        val apiResult = when {
                            // HTTP响应成功且业务响应存在
                            response.isSuccessful && baseResponse != null -> {
                                if (baseResponse.success) {
                                    ApiResult.Success(baseResponse.data)
                                } else {
                                    // 将错误码列表转换为Error对象列表
                                    val errors = baseResponse.errors.map { Error(it) }
                                    ApiResult.Failure(errors, baseResponse.data)
                                }
                            }
                            // HTTP响应失败(如4xx/5xx)
                            else -> {
                                val errors = listOf(Error(response.code(), "HTTP request failed"))
                                ApiResult.Failure(errors)
                            }
                        }
                        callback.onResponse(this@ApiResultCallAdapter, Response.success(apiResult))
                    }

                    override fun onFailure(call: Call<BaseResponseDto<T>>, t: Throwable) {
                        // 处理网络异常
                        val errors = listOf(Error(-1, t.message ?: "Network error"))
                        callback.onResponse(this@ApiResultCallAdapter, Response.success(ApiResult.Failure(errors)))
                    }
                })
            }

            override fun execute(): Response<ApiResult<T>> {
                val baseResponse = baseResponseCall.execute()
                val apiResult = baseResponse.body()?.let {
                    if (it.success) {
                        ApiResult.Success(it.data)
                    } else {
                        val errors = it.errors.map { code -> Error(code) }
                        ApiResult.Failure(errors, it.data)
                    }
                } ?: run {
                    val errors = listOf(Error(baseResponse.code(), "HTTP request failed"))
                    ApiResult.Failure(errors)
                }
                return Response.success(apiResult)
            }

            // 委托Call接口的其他方法给baseResponseCall
            override fun isExecuted(): Boolean = baseResponseCall.isExecuted
            override fun cancel() = baseResponseCall.cancel()
            override fun isCanceled(): Boolean = baseResponseCall.isCanceled
            override fun clone(): Call<ApiResult<T>> = ApiResultCallAdapter(delegate).adapt(call.clone())
            override fun request() = baseResponseCall.request()
        }
    }
}

3. 配置Retrofit实例

在构建Retrofit时添加自定义的ApiResultCallAdapterFactory,后续接口返回ApiResult<T>时,Retrofit会自动完成BaseResponseDto<T>的包装与转换:

val retrofit = Retrofit.Builder()
    .baseUrl("YOUR_BASE_API_URL")
    .addConverterFactory(GsonConverterFactory.create()) // 适配JSON序列化/反序列化,可替换为其他Converter
    .addCallAdapterFactory(ApiResultCallAdapterFactory())
    .build()

val apiService = retrofit.create(Api::class.java)

补充说明

  • 确保Error类有匹配的构造函数,比如:
    data class Error(val code: Int, val message: String? = null)
    
  • 若后端返回的字段名与BaseResponseDto不一致,需添加序列化注解(如Gson的@SerializedName)做映射。
  • 可根据业务需求调整错误处理逻辑,比如添加不同类型的错误分类、自定义错误信息等。

内容的提问来源于stack exchange,提问作者Farhan Farooqui

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:20:34