1

我有一个密封类来处理我的改造响应的状态。它的成员采用通用类型。我想让 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的启发,但我正在尝试将泛型添加到组合中,因此我不必手动将每个请求都放入接口中。有没有可能?我已经尝试了几个小时,也尝试为密封类构建适配器但失败了。有人有很好的资源如何做到这一点?

正如您在代码中看到的那样,我也希望能够接收列表。这里的任何提示也非常感谢。

4

0 回答 0