How to make RxErrorHandlingCallAdapterFactory?

I have found this .

But in the new compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0' in CallAdapter, it has two CallAdapter<?,?> parameters CallAdapter<?,?>

How to change RxCallAdapterWrapper for implement if from CallAdapter<?,?>

+7
source share
2 answers

Disclaimer: I am the author of the blog post you are linking to

The original post was intended as a proof of concept for RxJava 2, so it’s easier for me to explain this version, but I will try and cover more. I assume that you are using version 1, as you are talking about adapter-rxjava , not adapter-rxjava2 . However, the implementation for version 1 should be fairly simple and just use the right import.

Here is what I did using RxJava 2:

 class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory { private final RxJava2CallAdapterFactory original; private RxErrorHandlingCallAdapterFactory() { original = RxJava2CallAdapterFactory.create(); } public static CallAdapter.Factory create() { return new RxErrorHandlingCallAdapterFactory(); } @Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit)); } private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> { private final Retrofit retrofit; private final CallAdapter<R, Object> wrapped; public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<R, Object> wrapped) { this.retrofit = retrofit; this.wrapped = wrapped; } @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)); } }); } 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)); } }); } 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)); } }); } return result; } private RetrofitException asRetrofitException(Throwable 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); } } } 

No major changes, just some games with return types. Now, if you look at RxJava2CallAdapter , it implements CallAdapter<R, Object> , so we need to consider this.

Then I added some instance type checks to make sure that we are returning the right things.

An important role is to make sure that you import the correct packages. Reinstall adapters for specific classes. One of the problems I ran into had the wrong import and had situations when I checked if the Throwable instance was com.jakewharton.retrofit2.adapter.HttpException , although it was actually an instance of retrofit2.adapter.rxjava2.HttpException .

Hope this helps

+20
source

Updated Fred's answer on kotlin style and

rxjava1:

com.squareup.retrofit2:adapter-rxjava:2.5.0 io.reactivex:rxjava:1.3.8 with io.reactivex:rxjava:1.3.8

RxErrorHandlingCallAdapterFactory.kt

 import retrofit2.Call import retrofit2.CallAdapter import retrofit2.HttpException import retrofit2.Retrofit import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory import rx.Observable import java.io.IOException import java.lang.reflect.Type /** * Created by Nikolay Unuchek on 28.11.2016. */ internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() { private val original: RxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create() override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? { return RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit) ?: return null) } private class RxCallAdapterWrapper<R>( private val retrofit: Retrofit, private val wrapped: CallAdapter<R, *> ) : CallAdapter<R, Any> { override fun responseType(): Type { return wrapped.responseType() } override fun adapt(call: Call<R>): Any { val result = wrapped.adapt(call) if (result is Observable<*>) { return result.onErrorResumeNext { throwable -> Observable.error(asRetrofitException(throwable as Throwable)) } } return result } private fun asRetrofitException(throwable: Throwable): RetrofitException { // We had non-200 http error if (throwable is HttpException) { val response = throwable.response() return RetrofitException.httpError(response.raw().request.url.toString(), response, throwable) } // A network error happened return if (throwable is IOException) { RetrofitException.networkError(throwable) } else RetrofitException.unexpectedError(throwable) // We don't know what happened. We need to simply convert to an unknown error } } companion object { fun create(): CallAdapter.Factory { return RxErrorHandlingCallAdapterFactory() } } } 

RetrofitException.kt

 import retrofit2.HttpException import retrofit2.Response import java.io.IOException class RetrofitException private constructor( message: String?, /** * The request URL which produced the error. */ val url: String?, /** * Response object containing status code, headers, body, etc. */ val response: Response<*>?, /** * The event kind which triggered this error. */ val kind: Kind, exception: Throwable ) : RuntimeException(message, exception) { override fun toString(): String { return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string() } /** * Identifies the event kind which triggered a [RetrofitException]. */ enum class Kind { /** * An [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 } companion object { fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException { val message = response.code().toString() + " " + response.message() return RetrofitException(message, url, response, Kind.HTTP, httpException) } fun networkError(exception: IOException): RetrofitException { return RetrofitException(exception.message, null, null, Kind.NETWORK, exception) } fun unexpectedError(exception: Throwable): RetrofitException { return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception) } fun asRetrofitException(throwable: Throwable): RetrofitException { if (throwable is RetrofitException) { return throwable } // We had non-200 http error if (throwable is HttpException) { val response = throwable.response() return httpError(response.raw().request().url().toString(), response, throwable) } // A network error happened return if (throwable is IOException) { networkError(throwable) } else unexpectedError(throwable) // We don't know what happened. We need to simply convert to an unknown error } } } 

rxjava2:

com.squareup.retrofit2:adapter-rxjava2:2.6.0 with io.reactivex.rxjava2:rxjava:2.2.9

RxErrorHandlingCallAdapterFactory.kt

 import by.gramophone.api.errorhandling.RetrofitException.Companion.asRetrofitException import io.reactivex.Completable import io.reactivex.Observable import io.reactivex.Single import io.reactivex.functions.Function import retrofit2.Call import retrofit2.CallAdapter import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import java.lang.reflect.Type /** * Created by Nikolay Unuchek on 28.11.2016. */ internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() { private val original = RxJava2CallAdapterFactory.create() override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? { return RxCallAdapterWrapper(original.get(returnType, annotations, retrofit) ?: return null) } private class RxCallAdapterWrapper<R>(private val wrapped: CallAdapter<R, *>) : CallAdapter<R, Any> { override fun responseType(): Type { return wrapped.responseType() } override fun adapt(call: Call<R>): Any { return when (val result = wrapped.adapt(call)) { is Single<*> -> result.onErrorResumeNext(Function { throwable -> Single.error(asRetrofitException(throwable)) }) is Observable<*> -> result.onErrorResumeNext(Function { throwable -> Observable.error(asRetrofitException(throwable)) }) is Completable -> result.onErrorResumeNext (Function{ throwable -> Completable.error(asRetrofitException(throwable)) } ) else -> result } } } companion object { fun create(): CallAdapter.Factory { return RxErrorHandlingCallAdapterFactory() } } } 

RetrofitException.kt

 import retrofit2.HttpException import retrofit2.Response import java.io.IOException class RetrofitException private constructor( message: String?, /** * The request URL which produced the error. */ val url: String?, /** * Response object containing status code, headers, body, etc. */ val response: Response<*>?, /** * The event kind which triggered this error. */ val kind: Kind, exception: Throwable ) : RuntimeException(message, exception) { override fun toString(): String { return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string() } /** * Identifies the event kind which triggered a [RetrofitException]. */ enum class Kind { /** * An [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 } companion object { fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException { val message = response.code().toString() + " " + response.message() return RetrofitException(message, url, response, Kind.HTTP, httpException) } fun networkError(exception: IOException): RetrofitException { return RetrofitException(exception.message, null, null, Kind.NETWORK, exception) } fun unexpectedError(exception: Throwable): RetrofitException { return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception) } fun asRetrofitException(throwable: Throwable): RetrofitException { if (throwable is RetrofitException) { return throwable } // We had non-200 http error if (throwable is HttpException) { val response = throwable.response() return httpError(response.raw().request().url().toString(), response, throwable) } // A network error happened return if (throwable is IOException) { networkError(throwable) } else unexpectedError(throwable) // We don't know what happened. We need to simply convert to an unknown error } } } 
0
source

Source: https://habr.com/ru/post/1266347/


All Articles