Is it possible to know the called method when an error occurred?
Opened this issue · 11 comments
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:
- attach the call as a field in
HttpException
- create an exception that implements
CopyableThrowable
as suggested here: Kotlin/kotlinx.coroutines#1109
Any other suggestion?
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
I wii share it next week.
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.
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?