Skip to content

Instantly share code, notes, and snippets.

@llleodeleon
Created September 6, 2019 15:21
Show Gist options
  • Save llleodeleon/217efab69ec634782a1b6468323a835f to your computer and use it in GitHub Desktop.
Save llleodeleon/217efab69ec634782a1b6468323a835f to your computer and use it in GitHub Desktop.
Custom call adapter for Retrofit 2.6.0 + coroutines
class ResultCallAdapterFactory : 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(getRawType(resultType))
}
else -> null
}
}
else -> null
}
}
class ResultAdapter<T>(
private val clazz: Class<T>
): CallAdapter<T, Call<Result<T>>> {
override fun responseType() = clazz
override fun adapt(call: Call<T>): Call<Result<T>> = ResultCall(call)
}
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, Result<T>>(proxy) {
override fun enqueueImpl(callback: Callback<Result<T>>) = proxy.enqueue(object: Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val code = response.code()
val result = if (code in 200 until 300) {
val body = response.body()
Result.Success(body)
} else {
Result.Failure(code)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
override fun onFailure(call: Call<T>, t: Throwable) {
val result = if (t is IOException) {
Result.NetworkError
} else {
Result.Failure(null)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
})
override fun cloneImpl() = ResultCall(proxy.clone())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment