From b56cbb9446ca0bf770b8f1ff5de87b46e8e646b7 Mon Sep 17 00:00:00 2001 From: roman_tcaregorodtcev Date: Tue, 10 Dec 2019 16:51:25 +0300 Subject: [PATCH 1/2] CoroutineCallAdapterFactory refactored --- .../remote/CoroutineCallAdapterFactory.kt | 130 +++++------------- 1 file changed, 36 insertions(+), 94 deletions(-) diff --git a/lib/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt b/lib/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt index f99aec5..cea3980 100644 --- a/lib/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt +++ b/lib/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt @@ -1,121 +1,63 @@ package com.omega_r.base.remote -import com.squareup.moshi.Types.getRawType -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Job -import retrofit2.Call -import retrofit2.CallAdapter -import retrofit2.Callback -import retrofit2.HttpException -import retrofit2.Response -import retrofit2.Retrofit -import java.lang.reflect.ParameterizedType +import com.omega_r.libs.extensions.common.ifNull +import okhttp3.Request +import retrofit2.* import java.lang.reflect.Type -/** - * A [CallAdapter.Factory] for use with Kotlin coroutines. - * - * Adding this class to [Retrofit] allows you to return [Deferred] from - * service methods. - * - * interface MyService { - * @GET("user/me") - * Deferred<User> getUser() - * } - * - * There are two configurations supported for the [Deferred] type parameter: - * - * * Direct body (e.g., `Deferred`) returns the deserialized body for 2XX responses, throws - * [HttpException] errors for non-2XX responses, and throws [IOException][java.io.IOException] for - * network errors. - * * Response wrapped body (e.g., `Deferred>`) returns a [Response] object for all - * HTTP responses and throws [IOException][java.io.IOException] for network errors - */ -class CoroutineCallAdapterFactory (private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter.Factory() { - - - override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? { - if (Deferred::class.java != getRawType(returnType)) { - return null - } - if (returnType !is ParameterizedType) { - throw IllegalStateException( - "Deferred return type must be parameterized as Deferred or Deferred") - } - val responseType = getParameterUpperBound(0, returnType) - - val rawDeferredType = getRawType(responseType) - return if (rawDeferredType == Response::class.java) { - check(responseType is ParameterizedType) { "Response must be parameterized as Response or Response" } - ResponseCallAdapter(getParameterUpperBound(0, responseType), parent, errorConverter) - } else { - BodyCallAdapter(responseType, parent, errorConverter) - } +class CoroutineCallAdapterFactory(private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter.Factory() { + + override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? { + val callAdapter = retrofit.nextCallAdapter(this, returnType, annotations) + return CallAdapterWrapper(callAdapter) } - private class BodyCallAdapter(private val responseType: Type, - private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter> { + inner class CallAdapterWrapper(private val adapter: CallAdapter) : CallAdapter { - override fun responseType() = responseType + override fun adapt(call: Call): T = adapter.adapt(CallWrapper(call)) - override fun adapt(call: Call): Deferred { - val deferred = CompletableDeferred(parent) + override fun responseType(): Type = adapter.responseType() - deferred.invokeOnCompletion { - if (deferred.isCancelled) { - call.cancel() - } - } + } + + inner class CallWrapper(private val delegate: Call) : Call { + + override fun enqueue(callback: Callback) { + delegate.enqueue(object : Callback { - call.enqueue(object : Callback { - override fun onFailure(call: Call, t: Throwable) { - deferred.completeExceptionally(errorConverter?.invoke(t) ?: t) + override fun onFailure(call: Call, t: Throwable) { + callback.onFailure(call, errorConverter?.invoke(t) ?: t) } - override fun onResponse(call: Call, response: Response) { + override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { - deferred.complete(response.body()) + callback.onResponse(call, response) } else { - val httpException = HttpException(response) - deferred.completeExceptionally(errorConverter?.invoke(httpException) ?: httpException) + errorConverter?.invoke(HttpException(response))?.let { + callback.onFailure(call, it) + }.ifNull { + callback.onResponse(call, response) + } } } }) - return deferred } - } - private class ResponseCallAdapter(private val responseType: Type, - private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null - ) : CallAdapter>> { + override fun isExecuted(): Boolean = delegate.isExecuted - override fun responseType() = responseType + override fun clone(): Call = CallWrapper(delegate.clone()) - override fun adapt(call: Call): Deferred> { - val deferred = CompletableDeferred>(parent) + override fun isCanceled(): Boolean = delegate.isCanceled - deferred.invokeOnCompletion { - if (deferred.isCancelled) { - call.cancel() - } - } + override fun cancel() { + delegate.cancel() + } - call.enqueue(object : Callback { - override fun onFailure(call: Call, t: Throwable) { - deferred.completeExceptionally(errorConverter?.invoke(t) ?: t) - } + override fun execute(): Response = delegate.execute() - override fun onResponse(call: Call, response: Response) { - deferred.complete(response) - } - }) + override fun request(): Request = delegate.request() - return deferred - } } -} + +} \ No newline at end of file From d8e8f4282415907a6c3983b54a31505de5b54b50 Mon Sep 17 00:00:00 2001 From: roman_tcaregorodtcev Date: Mon, 16 Dec 2019 09:22:00 +0300 Subject: [PATCH 2/2] Default ErrorHandler for CoroutineCallAdapterFactory added --- .../com/omega_r/base/remote/CoroutineCallAdapterFactory.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt b/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt index cea3980..3f293c3 100644 --- a/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt +++ b/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt @@ -1,11 +1,12 @@ package com.omega_r.base.remote +import com.omega_r.base.errors.ErrorHandler import com.omega_r.libs.extensions.common.ifNull import okhttp3.Request import retrofit2.* import java.lang.reflect.Type -class CoroutineCallAdapterFactory(private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter.Factory() { +class CoroutineCallAdapterFactory(private val errorConverter: ((Throwable) -> Exception)? = ErrorHandler()) : CallAdapter.Factory() { override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? { val callAdapter = retrofit.nextCallAdapter(this, returnType, annotations)