我有一个密封类来处理我的改造响应的状态。它的成员采用通用类型。我想让 Retrofit 能够返回正确的对象,但我遇到了这个错误:Unable to create converter for com.my.app.DataResult<?> - Cannot serialize abstract class com.my.app.DataResult
这是我的 DataResult 类:
sealed class DataResult<out T> {
data class Success<out T>(val data: T?) : DataResult<T>()
data class Error<out T>(val code: Int? = null, val error: Exception? = null) : DataResult<T>()
object NetworkError : DataResult<Nothing>()
fun isSuccess() = this is Success<*>
fun isError() = this is Error<*>
fun data() = if (isSuccess()) (this as Success<T>).data else null
}
fun successResult() = DataResult.Success(null)
fun <T> successResult(data: T?) = DataResult.Success(data)
fun errorResult() = DataResult.Error<Nothing>(null)
这是我当前实现的其余部分:
class NetworkClient(private val httpClient: HttpClient) {
private val baseUrl: String = "some url"
private val retrofit = Retrofit.Builder()
.baseUrl(mockend)
.addCallAdapterFactory(MyCallAdapterFactory())
.addConverterFactory(MoshiConverterFactory.create())
.client(httpClient.get())
.build()
private val apiService: ApiService = retrofit.create(StaApiService::class.java)
suspend fun <T> sendGet(endPoint: EndPoint, input: String): DataResult<T> {
val result = apiService.sendGetRequest<T>(endPoint.stringValue, queryMapOf(Pair("query", input)))
when (result) {
// do stuff here?
}
return result
}
}
interface ApiService {
@GET
suspend fun <T> sendGetRequest(
@Url url: String,
@QueryMap parameters: Map<String, String>): DataResult<T>
@GET
suspend fun <T> sendGetListRequest(
@Url url: String,
@QueryMap parameters: Map<String, String>): DataResult<List<T>>
}
abstract class CallDelegate<TIn, TOut>(
protected val proxy: Call<TIn>
) : Call<TOut> {
override fun execute(): Response<TOut> = throw NotImplementedError()
final override fun enqueue(callback: Callback<TOut>) = enqueueImpl(callback)
final override fun clone(): Call<TOut> = cloneImpl()
override fun cancel() = proxy.cancel()
override fun request(): Request = proxy.request()
override fun isExecuted() = proxy.isExecuted
override fun isCanceled() = proxy.isCanceled
abstract fun enqueueImpl(callback: Callback<TOut>)
abstract fun cloneImpl(): Call<TOut>
}
class ResultCall<T>(proxy: Call<T>) : CallDelegate<T, DataResult<T>>(proxy) {
override fun enqueueImpl(callback: Callback<DataResult<T>>) = proxy.enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val code = response.code()
val result: DataResult<T> = if (code in 200 until 300) {
val body = response.body()
DataResult.Success(body)
} else {
DataResult.Error(code)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
override fun onFailure(call: Call<T>, t: Throwable) {
val result: DataResult<Nothing> = if (t is IOException) {
DataResult.NetworkError
} else {
DataResult.Error(null)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
})
override fun cloneImpl() = ResultCall(proxy.clone())
}
class ResultAdapter(
private val type: Type
) : CallAdapter<Type, Call<DataResult<Type>>> {
override fun responseType() = type
override fun adapt(call: Call<Type>): Call<DataResult<Type>> = ResultCall(call)
}
class MyCallAdapterFactory : CallAdapter.Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
) = when (getRawType(returnType)) {
Call::class.java -> {
val callType = getParameterUpperBound(0, returnType as ParameterizedType)
when (getRawType(callType)) {
Result::class.java -> {
val resultType = getParameterUpperBound(0, callType as ParameterizedType)
ResultAdapter(resultType)
}
else -> null
}
}
else -> null
}
}
上面的代码很大程度上是受this answer to another question的启发,但我正在尝试将泛型添加到组合中,因此我不必手动将每个请求都放入接口中。有没有可能?我已经尝试了几个小时,也尝试为密封类构建适配器但失败了。有人有很好的资源如何做到这一点?
正如您在代码中看到的那样,我也希望能够接收列表。这里的任何提示也非常感谢。