Skip to content

Instantly share code, notes, and snippets.

@simform-solutions
Last active May 21, 2019 20:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save simform-solutions/4a464ba6b24ea89a7b3fe8f1b56bb895 to your computer and use it in GitHub Desktop.
Save simform-solutions/4a464ba6b24ea89a7b3fe8f1b56bb895 to your computer and use it in GitHub Desktop.
RxErrorHandlingCallAdaptorFactory+RxJava2 global retrofit error handler.
import com.google.gson.stream.MalformedJsonException;
import java.io.IOException;
import java.lang.annotation.Annotation;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Response;
import retrofit2.Retrofit;
public class RetrofitException extends RuntimeException {
private final String url;
private final Response response;
private final Kind kind;
private final Retrofit retrofit;
public static RetrofitException httpError(String url, Response response, Retrofit retrofit) {
String message = response.code() + " " + response.message();
return new RetrofitException(message, url, response, Kind.HTTP, null, retrofit);
}
public static RetrofitException networkError(IOException exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.NETWORK, exception, null);
}
public static RetrofitException malformedJsonError(MalformedJsonException exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.NETWORK, exception, null);
}
public static RetrofitException unexpectedError(Throwable exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.UNEXPECTED, exception, null);
}
public enum Kind {
/**
* An {@link IOException} occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
private RetrofitException(String message, String url, Response response, Kind kind, Throwable exception, Retrofit retrofit) {
super(message, exception);
this.url = url;
this.response = response;
this.kind = kind;
this.retrofit = retrofit;
}
/**
* The request URL which produced the error.
*/
public String getUrl() {
return url;
}
/**
* Response object containing status code, headers, body, etc.
*/
public Response getResponse() {
return response;
}
/**
* The event kind which triggered this error.
*/
public Kind getKind() {
return kind;
}
/**
* The Retrofit this request was executed on
*/
public Retrofit getRetrofit() {
return retrofit;
}
/**
* HTTP response body converted to specified {@code type}. {@code null} if there is no
* response.
*
* @throws IOException if unable to convert the body to the specified {@code type}.
*/
public <T> T getErrorBodyAs(Class<T> type) throws IOException {
if (response == null || response.errorBody() == null) {
return null;
}
Converter<ResponseBody, T> converter = retrofit.responseBodyConverter(type, new Annotation[0]);
return converter.convert(response.errorBody());
}
}
import android.app.Activity;
import android.content.Context;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.UnknownHostException;
import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.HttpException;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
public class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
public Context context;
private RxJava2CallAdapterFactory original;
public RxErrorHandlingCallAdapterFactory(Context context) {
this.context = context;
original = RxJava2CallAdapterFactory.create();
}
public RxErrorHandlingCallAdapterFactory() {
original = RxJava2CallAdapterFactory.create();
}
public static CallAdapter.Factory create(Context context) {
return new RxErrorHandlingCallAdapterFactory();
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit), context);
}
private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> {
private final Retrofit retrofit;
private final CallAdapter<R, Object> wrapped;
private Context context;
public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<R, Object> wrapped, Context context) {
this.retrofit = retrofit;
this.wrapped = wrapped;
this.context = context;
}
@Override
public Type responseType() {
return wrapped.responseType();
}
@Override
public Object adapt(Call<R> call) {
Object result = wrapped.adapt(call);
if (result instanceof Single) {
return ((Single) result).onErrorResumeNext(new Function<Throwable, SingleSource>() {
@Override
public SingleSource apply(@NonNull Throwable throwable) throws Exception {
return Single.error(asRetrofitException(throwable, context));
}
});
}
if (result instanceof Observable) {
return ((Observable) result).onErrorResumeNext(new Function<Throwable, ObservableSource>() {
@Override
public ObservableSource apply(@NonNull Throwable throwable) throws Exception {
return Observable.error(asRetrofitException(throwable, context));
}
});
}
if (result instanceof Completable) {
return ((Completable) result).onErrorResumeNext(new Function<Throwable, CompletableSource>() {
@Override
public CompletableSource apply(@NonNull Throwable throwable) throws Exception {
return Completable.error(asRetrofitException(throwable, context));
}
});
}
return result;
}
private RetrofitException asRetrofitException(Throwable throwable, Context context) {
if (throwable instanceof UnknownHostException) {
return RetrofitException.networkError((IOException) throwable);
}
// We had non-200 http error
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
Response response = httpException.response();
return RetrofitException.httpError(response.raw().request().url().toString(), response, retrofit);
}
// A network error happened
if (throwable instanceof IOException) {
return RetrofitException.networkError((IOException) throwable);
}
// We don't know what happened. We need to simply convert to an unknown error
return RetrofitException.unexpectedError(throwable);
}
}
}
@mustanshir
Copy link

mustanshir commented May 7, 2018

'retrofit2.adapter.rxjava2.HttpException' class is deprecated instead we should use 'retrofit2.HttpException' class

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment