Created
November 3, 2022 13:08
-
-
Save G00fY2/b89d07963431e44edf1564b0edb55bea to your computer and use it in GitHub Desktop.
CustomRxJava3CallAdapterFactory to transform HttpExceptions to custom error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.squareup.moshi.Moshi | |
import io.reactivex.rxjava3.core.Completable | |
import io.reactivex.rxjava3.core.Flowable | |
import io.reactivex.rxjava3.core.Maybe | |
import io.reactivex.rxjava3.core.Observable | |
import io.reactivex.rxjava3.core.Scheduler | |
import io.reactivex.rxjava3.core.Single | |
import io.reactivex.rxjava3.schedulers.Schedulers | |
import retrofit2.Call | |
import retrofit2.CallAdapter | |
import retrofit2.CallAdapter.Factory | |
import retrofit2.HttpException | |
import retrofit2.Response | |
import retrofit2.Retrofit | |
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory | |
import timber.log.Timber | |
import java.lang.reflect.Type | |
class CustomRxJava3CallAdapterFactory( | |
scheduler: Scheduler = Schedulers.io(), | |
private val moshi: Moshi = Moshi.Builder().build() | |
) : Factory() { | |
private val original: RxJava3CallAdapterFactory = RxJava3CallAdapterFactory.createWithScheduler(scheduler) | |
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *> = | |
RxCallAdapterWrapper(original[returnType, annotations, retrofit]!!) | |
private inner class RxCallAdapterWrapper<R>(private val wrapped: CallAdapter<R, *>) : CallAdapter<R, Any> { | |
override fun responseType(): Type = wrapped.responseType() | |
override fun adapt(call: Call<R>): Any { | |
return when (val result = wrapped.adapt(call)) { | |
is Observable<*> -> result.onErrorResumeNext { Observable.error(transformException(it, call)) } | |
is Single<*> -> result.onErrorResumeNext { Single.error(transformException(it, call)) } | |
is Completable -> result.onErrorResumeNext { Completable.error(transformException(it, call)) } | |
is Maybe<*> -> result.onErrorResumeNext { Maybe.error(transformException(it, call)) } | |
is Flowable<*> -> result.onErrorResumeNext { Flowable.error(transformException(it, call)) } | |
else -> result | |
} | |
} | |
} | |
private fun transformException(throwable: Throwable, call: Call<*>): Throwable { | |
// We can also access the initial call.request().url() e.g. to detect which route caused an exception | |
if (throwable is HttpException) { | |
var apiError: MyCustomError? = null | |
val response: Response<*>? = throwable.response() | |
val errorBody = response?.errorBody() | |
if (errorBody != null) { | |
try { | |
apiError = moshi.adapter(MyCustomError::class.java).fromJson(errorBody.string()) | |
} catch (e: Exception) { | |
Timber.e(e) | |
} | |
if (apiError != null) { | |
return apiError | |
} | |
} | |
} | |
return throwable | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment