Skip to content

Instantly share code, notes, and snippets.

@kobito-kaba
Created May 27, 2021 04:23
Show Gist options
  • Save kobito-kaba/1c209f01a74d190beb771ba7567a4d91 to your computer and use it in GitHub Desktop.
Save kobito-kaba/1c209f01a74d190beb771ba7567a4d91 to your computer and use it in GitHub Desktop.
Retrofit supports kotlin Result
package com.example.retrofit
import okhttp3.Request
import okio.Timeout
import retrofit2.*
import java.io.IOException
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.concurrent.Executor
class KotlinResultCallAdapterFactory(private val executor: Executor) : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array<out Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
if (getRawType(returnType) != Call::class.java || returnType !is ParameterizedType) {
return null
}
val upperBound = getParameterUpperBound(0, returnType)
return if (upperBound is ParameterizedType && upperBound.rawType == Result::class.java) {
object : CallAdapter<Any, Call<Result<*>>> {
override fun responseType(): Type = getParameterUpperBound(0, upperBound)
override fun adapt(call: Call<Any>): Call<Result<*>> = ExecutorCallbackCall(executor, call) as Call<Result<*>>
}
} else {
null
}
}
private class ExecutorCallbackCall<T>(val callbackExecutor: Executor, val delegate: Call<T>) : Call<Result<T>> {
override fun enqueue(callback: Callback<Result<T>>) {
delegate.enqueue(
object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
callbackExecutor.execute {
if (delegate.isCanceled) {
callback.onResponse(this@ExecutorCallbackCall, Response.success(Result.failure(IOException("Canceled"))))
} else {
if (response.isSuccessful) {
callback.onResponse(this@ExecutorCallbackCall, Response.success(response.code(), Result.success(response.body()!!)))
} else {
callback.onResponse(this@ExecutorCallbackCall, Response.success(Result.failure(HttpException(response))))
}
}
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
callbackExecutor.execute {
callback.onResponse(this@ExecutorCallbackCall, Response.success(Result.failure(t)))
}
}
})
}
override fun isExecuted(): Boolean {
return delegate.isExecuted
}
override fun execute(): Response<Result<T>> {
return Response.success(Result.success(delegate.execute().body()!!))
}
override fun cancel() {
delegate.cancel()
}
override fun isCanceled(): Boolean {
return delegate.isCanceled
}
override fun clone(): Call<Result<T>> {
return ExecutorCallbackCall(callbackExecutor, delegate.clone())
}
override fun request(): Request {
return delegate.request()
}
override fun timeout(): Timeout {
return delegate.timeout()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment