Last active
October 2, 2024 04:13
-
-
Save G00fY2/a67d2e724bb3929c9a89c17a6f2c5ada to your computer and use it in GitHub Desktop.
CustomRxJava2CallAdapterFactory to transform HttpExceptions to custom error
This file contains 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.google.gson.Gson; | |
import io.reactivex.Completable; | |
import io.reactivex.Flowable; | |
import io.reactivex.Maybe; | |
import io.reactivex.MaybeSource; | |
import io.reactivex.Observable; | |
import io.reactivex.ObservableSource; | |
import io.reactivex.Scheduler; | |
import io.reactivex.Single; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Type; | |
import retrofit2.Call; | |
import retrofit2.CallAdapter; | |
import retrofit2.HttpException; | |
import retrofit2.Response; | |
import retrofit2.Retrofit; | |
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; | |
import timber.log.Timber; | |
@SuppressWarnings("unused") | |
public class CustomRxJava2CallAdapterFactory extends CallAdapter.Factory { | |
private final RxJava2CallAdapterFactory originalFactory; | |
private final Gson gson = new Gson(); | |
public static CustomRxJava2CallAdapterFactory create() { | |
return new CustomRxJava2CallAdapterFactory(null); | |
} | |
public static CallAdapter.Factory createWithScheduler(Scheduler scheduler) { | |
return new CustomRxJava2CallAdapterFactory(scheduler); | |
} | |
private CustomRxJava2CallAdapterFactory(Scheduler scheduler) { | |
if (scheduler == null) { | |
originalFactory = RxJava2CallAdapterFactory.create(); | |
} else { | |
originalFactory = RxJava2CallAdapterFactory.createWithScheduler(scheduler); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { | |
return new RxCallAdapterWrapper(originalFactory.get(returnType, annotations, retrofit), gson); | |
} | |
private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> { | |
private final CallAdapter<R, Object> wrapped; | |
private Gson gson; | |
RxCallAdapterWrapper(CallAdapter<R, Object> wrapped, Gson gson) { | |
this.wrapped = wrapped; | |
this.gson = gson; | |
} | |
@Override public Type responseType() { | |
return wrapped.responseType(); | |
} | |
@SuppressWarnings("unchecked") | |
@Override public Object adapt(Call<R> call) { | |
Object object = wrapped.adapt(call); | |
if (object instanceof Observable<?>) { | |
return ((Observable<?>) object).onErrorResumeNext( | |
(ObservableSource) throwable -> Observable.error(transformException((Throwable) throwable, call))); | |
} else if (object instanceof Single<?>) { | |
return ((Single<?>) object).onErrorResumeNext(throwable -> Single.error(transformException(throwable, call))); | |
} else if (object instanceof Completable) { | |
return ((Completable) object).onErrorResumeNext( | |
throwable -> Completable.error(transformException((Throwable) throwable, call))); | |
} else if (object instanceof Maybe<?>) { | |
return ((Maybe<?>) object).onErrorResumeNext( | |
(MaybeSource) throwable -> Maybe.error(transformException((Throwable) throwable, call))); | |
} else if (object instanceof Flowable<?>) { | |
return ((Flowable<?>) object).onErrorResumeNext(throwable -> { | |
return Flowable.error(transformException(throwable, call)); | |
}); | |
} | |
return object; | |
} | |
private Throwable transformException(Throwable throwable, Call call) { | |
// We can also access the initial call.request().url() e.g. to detect which route caused an exception | |
if (throwable instanceof HttpException) { | |
MyCustomError apiError = null; | |
Response<?> response = ((HttpException) throwable).response(); | |
if (response.errorBody() != null) { | |
try { | |
apiError = gson.fromJson(response.errorBody().string(), MyCustomError.class); | |
} catch (Exception e) { | |
Timber.d(e); | |
} | |
if (apiError != null) { | |
return apiError; | |
} | |
} | |
} | |
return throwable; | |
} | |
} | |
} |
You can find an RxJava3 Kotlin version of this adapter here: https://gist.github.com/G00fY2/b89d07963431e44edf1564b0edb55bea
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice!