JakeWharton/retrofit2-kotlin-coroutines-adapter

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

Opened this issue · 11 comments

oshai commented

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?

@oshai have you found any solutions?

oshai commented

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

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

oshai commented

I wii share it next week.

oshai commented

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)
    }
}

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

oshai commented

Yes, I am using try/catch.

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

Could you find a solution better than try/catch?

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

thanks @soulduse, your way is very helpful