Мне нужно создать модернизированный адаптер вызовов, который может обрабатывать такие сетевые вызовы:
@GET("user")
suspend fun getUser(): MyResponseWrapper<User>
Я хочу, чтобы он работал с Kotlin Coroutines без использования Deferred
. У меня уже есть успешная реализация с использованием Deferred
, который может обрабатывать такие методы, как:
@GET("user")
fun getUser(): Deferred<MyResponseWrapper<User>>
Но я хочу, чтобы эта функция сделала функцию приостановки и удалила Deferred
оболочку.
С функциями приостановки Retrofit работает так, как будто есть обертка Call
вокруг возвращаемого типа, поэтому suspend fun getUser(): User
рассматривается как fun getUser(): Call<User>
Моя реализация
Я попытался создать адаптер вызова, который пытается справиться с этим. Вот моя реализация до сих пор:
завод
class MyWrapperAdapterFactory : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
val rawType = getRawType(returnType)
if (rawType == Call::class.java) {
returnType as? ParameterizedType
?: throw IllegalStateException("$returnType must be parameterized")
val containerType = getParameterUpperBound(0, returnType)
if (getRawType(containerType) != MyWrapper::class.java) {
return null
}
containerType as? ParameterizedType
?: throw IllegalStateException("MyWrapper must be parameterized")
val successBodyType = getParameterUpperBound(0, containerType)
val errorBodyType = getParameterUpperBound(1, containerType)
val errorBodyConverter = retrofit.nextResponseBodyConverter<Any>(
null,
errorBodyType,
annotations
)
return MyWrapperAdapter<Any, Any>(successBodyType, errorBodyConverter)
}
return null
}
адаптер
class MyWrapperAdapter<T : Any>(
private val successBodyType: Type
) : CallAdapter<T, MyWrapper<T>> {
override fun adapt(call: Call<T>): MyWrapper<T> {
return try {
call.execute().toMyWrapper<T>()
} catch (e: IOException) {
e.toNetworkErrorWrapper()
}
}
override fun responseType(): Type = successBodyType
}
runBlocking {
val user: MyWrapper<User> = service.getUser()
}
С помощью этой реализации все работает, как и ожидалось, но непосредственно перед тем, как результат сетевого вызова будет доставлен в переменную user
, я получаю следующую ошибку:
java.lang.ClassCastException: com.myproject.MyWrapper cannot be cast to retrofit2.Call
at retrofit2.HttpServiceMethod$SuspendForBody.adapt(HttpServiceMethod.java:185)
at retrofit2.HttpServiceMethod.invoke(HttpServiceMethod.java:132)
at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
at com.sun.proxy.$Proxy6.getText(Unknown Source)
...
Из исходного кода, вот фрагмент кода в HttpServiceMethod.java:185
:
@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call); // ERROR OCCURS HERE
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
}
Я не уверен, как справиться с этой ошибкой. Есть ли способ исправить?