Last active
July 28, 2022 10:47
-
-
Save naturalwarren/d1a053707fa1b9987c1b0ff12f399d23 to your computer and use it in GitHub Desktop.
Retrofit 2 CallAdapterFactory that Wraps Network Errors
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
package com.uber.retrofit2.adapters.network.exception; | |
import android.support.annotation.NonNull; | |
import java.io.IOException; | |
import okhttp3.Call; | |
import okhttp3.Callback; | |
import okhttp3.Request; | |
/** | |
* Exception for unexpected, network errors. | |
*/ | |
public class NetworkException extends IOException { | |
private final Request request; | |
private final IOException ioException; | |
public NetworkException(@NonNull Request request, @NonNull IOException ioException) { | |
super(ioException.getMessage(), ioException.getCause()); | |
this.request = request; | |
this.ioException = ioException; | |
} | |
/** | |
* @return the {@link IOException} returned by {@link Call#execute()} or {@link Call#enqueue(Callback)}. | |
*/ | |
@NonNull | |
public IOException ioException() { | |
return ioException; | |
} | |
/** | |
* @return the {@link Request} that resulted in an error at the network level. | |
*/ | |
@NonNull | |
public Request request() { | |
return request; | |
} | |
} |
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
package com.uber.retrofit2.adapters.network.exception; | |
import android.support.annotation.NonNull; | |
import java.io.IOException; | |
import okhttp3.Request; | |
import retrofit2.Call; | |
import retrofit2.Callback; | |
import retrofit2.Response; | |
/** | |
* An {@link Call} that delegates to a backing Call and returns {@link NetworkException} when an {@link IOException} is | |
* encountered. | |
* @param <T> Successful response body type. | |
*/ | |
final class NetworkExceptionCall<T> implements Call<T> { | |
private final Call<T> delegateCall; | |
NetworkExceptionCall(@NonNull Call<T> delegateCall) { | |
this.delegateCall = delegateCall; | |
} | |
@Override | |
public Response<T> execute() throws IOException { | |
try { | |
return delegateCall.execute(); | |
} catch (IOException e) { | |
throw new NetworkException(request(), e); | |
} | |
} | |
@Override | |
public void enqueue(final Callback<T> callback) { | |
delegateCall.enqueue(new Callback<T>() { | |
@Override | |
public void onResponse(Call<T> call, Response<T> response) { | |
callback.onResponse(call, response); | |
} | |
@Override | |
public void onFailure(Call<T> call, Throwable t) { | |
if (t instanceof IOException) { | |
callback.onFailure(call, new NetworkException(request(), (IOException) t)); | |
} else { | |
callback.onFailure(call, t); | |
} | |
} | |
}); | |
} | |
@Override | |
public boolean isExecuted() { | |
return delegateCall.isExecuted(); | |
} | |
@Override | |
public void cancel() { | |
delegateCall.cancel(); | |
} | |
@Override | |
public boolean isCanceled() { | |
return delegateCall.isCanceled(); | |
} | |
// We are a final type & this saves clearing state. | |
@SuppressWarnings("CloneDoesntCallSuperClone") | |
@Override | |
public Call<T> clone() { | |
return new NetworkExceptionCall<>(delegateCall.clone()); | |
} | |
@Override | |
public Request request() { | |
return delegateCall.request(); | |
} | |
} |
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
package com.uber.retrofit2.adapters.network.exception; | |
import java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Type; | |
import okhttp3.Request; | |
import retrofit2.Call; | |
import retrofit2.CallAdapter; | |
import retrofit2.Callback; | |
import retrofit2.Retrofit; | |
/** | |
* A {@linkplain CallAdapter.Factory call adapter} that wraps {@link IOException} with its {@link Request} | |
* in {@link NetworkException}. | |
* | |
* NOTE: This is a forwarding adapter and delegates to another call adapter. It must be registered to your | |
* {@link Retrofit} instance before the adapter it delegates to. | |
*/ | |
public final class NetworkExceptionCallAdapterFactory extends CallAdapter.Factory { | |
/** | |
* @return an instance which will wrap any {@link IOException} with its corresponding {@link Request}. | |
*/ | |
public static NetworkExceptionCallAdapterFactory create() { | |
return new NetworkExceptionCallAdapterFactory(); | |
} | |
@Override | |
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { | |
return new NetworkExceptionCallAdapter(retrofit.nextCallAdapter(this, returnType, annotations)); | |
} | |
/** | |
* Wraps a delegate call adapter and passes on a {@link NetworkExceptionCall} which performs | |
* {@link IOException} wrapping when an error is encountered upon invoking | |
* {@link NetworkExceptionCall#enqueue(Callback)} or {@link NetworkExceptionCall#execute()}. | |
*/ | |
private static final class NetworkExceptionCallAdapter implements CallAdapter<Object> { | |
private final CallAdapter<?> delegateCallAdapter; | |
NetworkExceptionCallAdapter(CallAdapter<?> delegateCallAdapter) { | |
this.delegateCallAdapter = delegateCallAdapter; | |
} | |
@Override | |
public Type responseType() { | |
return delegateCallAdapter.responseType(); | |
} | |
@Override | |
public <R> Object adapt(Call<R> call) { | |
return delegateCallAdapter.adapt(new NetworkExceptionCall<>(call)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment