Мне нужно создать адаптер вызовов для модернизации, который может обрабатывать такие сетевые вызовы:
@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)
...
Из исходного кода Retrofit приведен фрагмент кода на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);
}
Я не уверен, как справиться с этой ошибкой.Есть ли способ исправить?