Created
April 5, 2017 21:31
-
-
Save autovalue/abe27912026ea5bf195187825fbd5ee2 to your computer and use it in GitHub Desktop.
Retrofit ConverterCallAdapterFactory implementation. A way to use the current request to convert the ResponseBody to a different class type.
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 java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.ParameterizedType; | |
import java.lang.reflect.Type; | |
import okhttp3.Request; | |
import okhttp3.ResponseBody; | |
import retrofit2.Call; | |
import retrofit2.CallAdapter; | |
import retrofit2.Callback; | |
import retrofit2.Response; | |
import retrofit2.Retrofit; | |
/** | |
* Heavily based off @NightlyNexus awesome work - https://github.com/square/retrofit/issues/2267#issuecomment-291915308 | |
* The converter must be the first entry in your {@link Retrofit.Builder#addCallAdapterFactory} call. | |
*/ | |
public final class ConverterCallAdapterFactory extends CallAdapter.Factory { | |
public interface ResponseBodyConverter<T> { | |
T convert(Request request, ResponseBody body) throws IOException; | |
interface Factory { | |
ResponseBodyConverter<?> responseBodyConverter(Type type, Annotation[] annotations, | |
Retrofit retrofit); | |
} | |
} | |
private final ResponseBodyConverter.Factory converterFactory; | |
public ConverterCallAdapterFactory(ResponseBodyConverter.Factory converterFactory) { | |
this.converterFactory = converterFactory; | |
} | |
@Override | |
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { | |
// noinspection unchecked | |
final CallAdapter<Object, ?> delegate = | |
(CallAdapter<Object, ?>) retrofit.nextCallAdapter(this, returnType, annotations); | |
// noinspection unchecked | |
final CallAdapter<Object, Call<ResponseBody>> bodyCallAdapter = | |
(CallAdapter<Object, Call<ResponseBody>>) retrofit.nextCallAdapter(this, | |
new ParameterizedType() { | |
@Override | |
public Type[] getActualTypeArguments() { | |
return new Type[]{ResponseBody.class}; | |
} | |
@Override | |
public Type getRawType() { | |
return Call.class; | |
} | |
@Override | |
public Type getOwnerType() { | |
return null; | |
} | |
}, annotations); | |
final Type responseType = delegate.responseType(); | |
// noinspection unchecked | |
final ResponseBodyConverter<Object> converter = | |
(ResponseBodyConverter<Object>) converterFactory.responseBodyConverter(responseType, | |
annotations, retrofit); | |
return new CallAdapter<Object, Object>() { | |
@Override | |
public Type responseType() { | |
return responseType; | |
} | |
@Override | |
public Object adapt(Call<Object> call) { | |
return delegate.adapt(new ConverterCall<>(bodyCallAdapter.adapt(call), converter)); | |
} | |
}; | |
} | |
private static final class ConverterCall<T> implements Call<T> { | |
private final Call<ResponseBody> delegate; | |
final ResponseBodyConverter<T> converter; | |
ConverterCall(Call<ResponseBody> delegate, ResponseBodyConverter<T> converter) { | |
this.delegate = delegate; | |
this.converter = converter; | |
} | |
@Override | |
public Response<T> execute() throws IOException { | |
Response<ResponseBody> response = delegate.execute(); | |
okhttp3.Response raw = response.raw(); | |
if (raw.isSuccessful()) { | |
return Response.success(converter.convert(delegate.request(), response.body()), raw); | |
} | |
return Response.error(raw.body(), raw); | |
} | |
@Override | |
public void enqueue(final Callback<T> callback) { | |
delegate.enqueue(new Callback<ResponseBody>() { | |
@Override | |
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { | |
okhttp3.Response raw = response.raw(); | |
Response<T> converted; | |
if (raw.isSuccessful()) { | |
try { | |
converted = | |
Response.success(converter.convert(call.request(), response.body()), raw); | |
} catch (IOException e) { | |
callback.onFailure(ConverterCall.this, e); | |
return; | |
} | |
} else { | |
converted = Response.error(raw.body(), raw); | |
} | |
callback.onResponse(ConverterCall.this, converted); | |
} | |
@Override | |
public void onFailure(Call<ResponseBody> call, Throwable t) { | |
callback.onFailure(ConverterCall.this, t); | |
} | |
}); | |
} | |
@Override | |
public boolean isExecuted() { | |
return delegate.isExecuted(); | |
} | |
@Override | |
public void cancel() { | |
delegate.cancel(); | |
} | |
@Override | |
public boolean isCanceled() { | |
return delegate.isCanceled(); | |
} | |
@Override | |
public Call<T> clone() { | |
return new ConverterCall<>(delegate.clone(), converter); | |
} | |
@Override | |
public Request request() { | |
return delegate.request(); | |
} | |
} | |
} |
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
public interface ExampleEndpoint { | |
@GET("{path}") | |
Observable<Document> document(@Path(value = "path", encoded = true) String path); | |
} |
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 org.jsoup.Jsoup; | |
import java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Type; | |
import okhttp3.Request; | |
import okhttp3.ResponseBody; | |
import retrofit2.Retrofit; | |
public class JsoupResponseBodyConverterFactory implements ConverterCallAdapterFactory.ResponseBodyConverter.Factory { | |
@Override | |
public ConverterCallAdapterFactory.ResponseBodyConverter<?> responseBodyConverter( | |
final Type type, Annotation[] annotations, Retrofit retrofit) { | |
return new ConverterCallAdapterFactory.ResponseBodyConverter<Object>() { | |
@Override | |
public Object convert(Request request, ResponseBody body) throws IOException { | |
return Jsoup.parse(body.string(), request.url().toString()); | |
} | |
}; | |
} | |
} |
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 java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Type; | |
import okhttp3.ResponseBody; | |
import retrofit2.Converter; | |
import retrofit2.Retrofit; | |
public class ResponseBodyConverter extends Converter.Factory { | |
@Override | |
public Converter<ResponseBody, ?> responseBodyConverter(Type type, | |
Annotation[] annotations, Retrofit retrofit) { | |
return new Converter<ResponseBody, Object>() { | |
@Override | |
public Object convert(ResponseBody value) throws IOException { | |
return value; | |
} | |
}; | |
} | |
} |
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
public class SampleUsage { | |
public OkHttpClient okHttpClient; | |
public void sampleUsage() { | |
Retrofit.Builder builder = new Retrofit.Builder() | |
.baseUrl("http://square.github.io") | |
.client(okHttpClient) | |
.addCallAdapterFactory(new ConverterCallAdapterFactory(new JsoupResponseBodyConverterFactory())) | |
.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io())) | |
.addConverterFactory(new ResponseBodyConverter()); | |
Retrofit retrofit = builder.build(); | |
ExampleEndpoint exampleEndpoint = retrofit.create(ExampleEndpoint.class); | |
exampleEndpoint.document("retrofit/").map(new Func1<Document, String>() { | |
@Override | |
public String call(Document document) { | |
return document.title(); | |
} | |
}).subscribe(new Subscriber<String>() { | |
@Override | |
public void onCompleted() {} | |
@Override | |
public void onError(Throwable e) { | |
Timber.e(e, "Unexpected error"); | |
ToastHelper.toast(e.getMessage(), false); | |
} | |
@Override | |
public void onNext(String s) { | |
ToastHelper.toast(s, false); | |
} | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment