如何让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
相关产品推荐
相关产品推荐

