JakeWharton / retrofit2-kotlin-coroutines-adapter

A Retrofit 2 adapter for Kotlin coroutine's Deferred type.
Apache License 2.0
1.97k stars 129 forks source link

Is it possible to know the called method when an error occurred? #48

Open oshai opened 5 years ago

oshai commented 5 years ago

When an error occurs on Deferred.await() the thrown error stacktrace is not showing any indication of the url/method that was actually called:

Exception in thread "main" retrofit2.HttpException: HTTP 404 Not Found
    at com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory$BodyCallAdapter$adapt$2.onResponse(CoroutineCallAdapterFactory.kt:104)
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:129)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

The code that produces it is this:

import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import kotlinx.coroutines.Deferred
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Retrofit
import retrofit2.http.GET

suspend fun main() {
    createService("http://www.google.com/", MyService::class.java)
        .run()
        .await()
}

fun <T> createService(baseUrl: String, clazz: Class<T>): T {
    val httpClient = OkHttpClient.Builder().build()
    val retrofit = Retrofit.Builder().baseUrl(baseUrl)
        //for coroutines deferred
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .client(httpClient).build()
    return retrofit.create(clazz)
}

interface MyService {

    @GET("blabla")
    fun run(): Deferred<ResponseBody>
}

I am thinking here of a couple of alternatives:

Any other suggestion?

dinhtho commented 5 years ago

@oshai have you found any solutions?

oshai commented 5 years ago

I forked the repo and changed it. Found out that the codebase is about one file so it's pretty straightforward.

dinhtho commented 5 years ago

How did you change code, can you show it?. I'm a newbie in Kotlin

oshai commented 5 years ago

I wii share it next week.

oshai commented 5 years ago

I changed this line like this:

override fun onResponse(call: Call<T>, response: Response<T>) {
                    if (response.isSuccessful) {
                        deferred.complete(response.body()!!)
                    } else {
                        deferred.completeExceptionally(RetrofitException("Error ${response.code()} ${response.message()} in ${call.request().method()}: '${call.request().url()}'", HttpException(response)))
                    }
                }

And added this class:

class RetrofitException(private val requestMessage: String ,private val httpException: HttpException): Exception(requestMessage, httpException), CopyableThrowable<RetrofitException> {
    override fun createCopy(): RetrofitException {
        return  RetrofitException(requestMessage, httpException)
    }
}
dinhtho commented 5 years ago

Thanks Did you use try catch to catch errors? I'm using it, but I found it was too lengthy.

oshai commented 5 years ago

Yes, I am using try/catch.

dinhtho commented 5 years ago

Ok, thank you, I think it will better if we have an error function like in RxAndroid to catch errors :(

hosseinaminii commented 5 years ago

Could you find a solution better than try/catch?

soulduse commented 5 years ago

I'm using this way https://gist.github.com/soulduse/b832152e42b893581f7736f4524f3dcd What do you think about this code?

dinhtho commented 5 years ago

thanks @soulduse, your way is very helpful