forked from square/retrofit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce call, call adapters, and the response type.
* `Call` is the mechanism for request execution. It encapsulates a single request action either synchronously or asynchronously, and can support canceling. * `CallAdapter` is a means of supporting a method return type other than `Call` (like RxJava's `Observable`) by adapting the `Call` instance into another instance. This change moves RxJava support into a sibling module which uses an adapter for supporting `Observable` types. * `Response` represents the HTTP response along side the deserialized body. It allows access to both the converted body and lower-level items such as the header, response code, and underlying OkHttp request and response objects.
- Loading branch information
1 parent
87dd2c6
commit 2ca1950
Showing
42 changed files
with
2,078 additions
and
1,983 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Retrofit Adapters | ||
================= | ||
|
||
TODO |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.squareup.retrofit</groupId> | ||
<artifactId>parent</artifactId> | ||
<version>2.0.0-SNAPSHOT</version> | ||
<relativePath>../pom.xml</relativePath> | ||
</parent> | ||
|
||
<artifactId>retrofit-adapters</artifactId> | ||
<name>Adapters</name> | ||
<packaging>pom</packaging> | ||
|
||
<modules> | ||
<module>rxjava</module> | ||
</modules> | ||
</project> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.squareup.retrofit</groupId> | ||
<artifactId>retrofit-adapters</artifactId> | ||
<version>2.0.0-SNAPSHOT</version> | ||
<relativePath>../pom.xml</relativePath> | ||
</parent> | ||
|
||
<artifactId>adapter-rxjava</artifactId> | ||
<name>Adapter: RxJava</name> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.squareup.retrofit</groupId> | ||
<artifactId>retrofit</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.reactivex</groupId> | ||
<artifactId>rxjava</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
185 changes: 185 additions & 0 deletions
185
retrofit-adapters/rxjava/src/main/java/retrofit/ObservableCallAdapterFactory.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package retrofit; | ||
|
||
import java.io.IOException; | ||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import rx.Observable; | ||
import rx.Subscriber; | ||
import rx.functions.Action0; | ||
import rx.functions.Func1; | ||
import rx.subscriptions.Subscriptions; | ||
|
||
/** | ||
* TODO docs | ||
*/ | ||
public final class ObservableCallAdapterFactory implements CallAdapter.Factory { | ||
/** | ||
* TODO | ||
*/ | ||
public static ObservableCallAdapterFactory create() { | ||
return new ObservableCallAdapterFactory(); | ||
} | ||
|
||
private ObservableCallAdapterFactory() { | ||
} | ||
|
||
@Override public String toString() { | ||
return getClass().getSimpleName(); | ||
} | ||
|
||
@Override public CallAdapter<?> get(Type returnType) { | ||
if (Utils.getRawType(returnType) != Observable.class) { | ||
return null; | ||
} | ||
if (!(returnType instanceof ParameterizedType)) { | ||
throw new IllegalStateException("Observable return type must be parameterized" | ||
+ " as Observable<Foo> or Observable<? extends Foo>"); | ||
} | ||
|
||
Type observableType = Utils.getSingleParameterUpperBound((ParameterizedType) returnType); | ||
Class<?> rawObservableType = Utils.getRawType(observableType); | ||
|
||
if (rawObservableType == Response.class) { | ||
if (!(observableType instanceof ParameterizedType)) { | ||
throw new IllegalStateException("Response must be parameterized" | ||
+ " as Response<Foo> or Response<? extends Foo>"); | ||
} | ||
Type responseType = Utils.getSingleParameterUpperBound((ParameterizedType) observableType); | ||
return new ResponseCallAdapter<>(responseType); | ||
} | ||
|
||
if (rawObservableType == Result.class) { | ||
if (!(observableType instanceof ParameterizedType)) { | ||
throw new IllegalStateException("Result must be parameterized" | ||
+ " as Result<Foo> or Result<? extends Foo>"); | ||
} | ||
Type responseType = Utils.getSingleParameterUpperBound((ParameterizedType) observableType); | ||
return new ResultCallAdapter<>(responseType); | ||
} | ||
|
||
return new SimpleCallAdapter(observableType); | ||
} | ||
|
||
static final class CallOnSubcribe<T> implements Observable.OnSubscribe<Response<T>> { | ||
private final Call<T> originalCall; | ||
|
||
private CallOnSubcribe(Call<T> originalCall) { | ||
this.originalCall = originalCall; | ||
} | ||
|
||
@Override public void call(final Subscriber<? super Response<T>> subscriber) { | ||
// Since Call is a one-shot type, clone it for each new subscriber. | ||
final Call<T> call = originalCall.clone(); | ||
|
||
// Attempt to cancel the call if it is still in-flight on unsubscription. | ||
subscriber.add(Subscriptions.create(new Action0() { | ||
@Override public void call() { | ||
call.cancel(); | ||
} | ||
})); | ||
|
||
call.enqueue(new Callback<T>() { | ||
@Override public void success(Response<T> response) { | ||
if (subscriber.isUnsubscribed()) { | ||
return; | ||
} | ||
try { | ||
subscriber.onNext(response); | ||
} catch (Throwable t) { | ||
subscriber.onError(t); | ||
return; | ||
} | ||
subscriber.onCompleted(); | ||
} | ||
|
||
@Override public void failure(Throwable t) { | ||
if (subscriber.isUnsubscribed()) { | ||
return; | ||
} | ||
subscriber.onError(t); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
static final class ResponseCallAdapter<T> implements CallAdapter<T> { | ||
private final Type responseType; | ||
|
||
ResponseCallAdapter(Type responseType) { | ||
this.responseType = responseType; | ||
} | ||
|
||
@Override public Type responseType() { | ||
return responseType; | ||
} | ||
|
||
@Override public Observable<Response<T>> adapt(Call<T> call) { | ||
return Observable.create(new CallOnSubcribe<>(call)); | ||
} | ||
} | ||
|
||
static final class SimpleCallAdapter<T> implements CallAdapter<T> { | ||
private final Type responseType; | ||
|
||
SimpleCallAdapter(Type responseType) { | ||
this.responseType = responseType; | ||
} | ||
|
||
@Override public Type responseType() { | ||
return responseType; | ||
} | ||
|
||
@Override public Observable<T> adapt(Call<T> call) { | ||
return Observable.create(new CallOnSubcribe<>(call)) // | ||
.flatMap(new Func1<Response<T>, Observable<T>>() { | ||
@Override public Observable<T> call(Response<T> response) { | ||
if (response.isSuccess()) { | ||
return Observable.just(response.body()); | ||
} | ||
return Observable.error(new IOException()); // TODO non-suck message. | ||
} | ||
}); | ||
} | ||
} | ||
|
||
static final class ResultCallAdapter<T> implements CallAdapter<T> { | ||
private final Type responseType; | ||
|
||
ResultCallAdapter(Type responseType) { | ||
this.responseType = responseType; | ||
} | ||
|
||
@Override public Type responseType() { | ||
return responseType; | ||
} | ||
|
||
@Override public Observable<Result<T>> adapt(Call<T> call) { | ||
return Observable.create(new CallOnSubcribe<>(call)) // | ||
.map(new Func1<Response<T>, Result<T>>() { | ||
@Override public Result<T> call(Response<T> response) { | ||
return Result.fromResponse(response); | ||
} | ||
}) | ||
.onErrorReturn(new Func1<Throwable, Result<T>>() { | ||
@Override public Result<T> call(Throwable throwable) { | ||
return Result.fromError(throwable); | ||
} | ||
}); | ||
} | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
retrofit-adapters/rxjava/src/main/java/retrofit/Result.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package retrofit; | ||
|
||
import java.io.IOException; | ||
|
||
import static retrofit.Utils.checkNotNull; | ||
|
||
/** The result of executing an HTTP request. */ | ||
public final class Result<T> { | ||
static <T> Result<T> fromError(Throwable error) { | ||
return new Result<>(null, checkNotNull(error, "error == null")); | ||
} | ||
|
||
static <T> Result<T> fromResponse(Response<T> response) { | ||
return new Result<>(checkNotNull(response, "response == null"), null); | ||
} | ||
|
||
private final Response<T> response; | ||
private final Throwable error; | ||
|
||
Result(Response<T> response, Throwable error) { | ||
this.response = response; | ||
this.error = error; | ||
} | ||
|
||
/** | ||
* The response received from executing an HTTP request. Only present when {@link #isError()} is | ||
* false, null otherwise. | ||
*/ | ||
public Response<T> response() { | ||
return response; | ||
} | ||
|
||
/** | ||
* The error experienced while attempting to execute an HTTP request. Only present when {@link | ||
* #isError()} is true, null otherwise. | ||
* <p> | ||
* If the error is an {@link IOException} then there was a problem with the transport to the | ||
* remote server. Any other exception type indicates an unexpected failure and should be | ||
* considered fatal (configuration error, programming error, etc.). | ||
*/ | ||
public Throwable error() { | ||
return error; | ||
} | ||
|
||
/** {@code true} if the request resulted in an error. See {@link #error()} for the cause. */ | ||
public boolean isError() { | ||
return error != null; | ||
} | ||
} |
Oops, something went wrong.