Skip to content

Commit

Permalink
Guava gone (Azure#477)
Browse files Browse the repository at this point in the history
* Try removing TypeToken

* Fix all tests

* Use TypeUtil

* Simply getTypeArgument

* Move things a little bit

* Progress on HTTPS proxying

* Fix Azure compile error

* Simplify netty pipeline and reduce possibility of corruption

* Fix build error

* Remove type factory

* Checkstyle

* Clean up
  • Loading branch information
jianghaolu authored Aug 23, 2018
1 parent 34fa182 commit 057546c
Show file tree
Hide file tree
Showing 16 changed files with 395 additions and 342 deletions.
1 change: 1 addition & 0 deletions client-runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
Expand Down
54 changes: 20 additions & 34 deletions client-runtime/src/main/java/com/microsoft/rest/v2/RestProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package com.microsoft.rest.v2;

import com.google.common.reflect.TypeToken;
import com.microsoft.rest.v2.annotations.ResumeOperation;
import com.microsoft.rest.v2.credentials.ServiceClientCredentials;
import com.microsoft.rest.v2.http.ContentType;
Expand All @@ -29,6 +28,7 @@
import com.microsoft.rest.v2.protocol.SerializerEncoding;
import com.microsoft.rest.v2.serializer.JacksonAdapter;
import com.microsoft.rest.v2.util.FlowableUtil;
import com.microsoft.rest.v2.util.TypeUtil;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
Expand All @@ -41,7 +41,6 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.URL;
Expand Down Expand Up @@ -204,7 +203,7 @@ private HttpRequest createHttpRequest(SwaggerMethodParser methodParser, Object[]
final String bodyContentString = serializer.serialize(bodyContentObject, SerializerEncoding.JSON);
request.withBody(bodyContentString);
}
else if (FlowableUtil.isFlowableByteBuffer(TypeToken.of(methodParser.bodyJavaType()))) {
else if (FlowableUtil.isFlowableByteBuffer(methodParser.bodyJavaType())) {
// Content-Length or Transfer-Encoding: chunked must be provided by a user-specified header when a Flowable<byte[]> is given for the body.
//noinspection ConstantConditions
request.withBody((Flowable<ByteBuffer>) bodyContentObject);
Expand Down Expand Up @@ -276,7 +275,7 @@ private HttpRequest createHttpRequest(OperationDescription operationDescription,
final String bodyContentString = serializer.serialize(bodyContentObject, SerializerEncoding.JSON);
request.withBody(bodyContentString);
}
else if (FlowableUtil.isFlowableByteBuffer(TypeToken.of(methodParser.bodyJavaType()))) {
else if (FlowableUtil.isFlowableByteBuffer(methodParser.bodyJavaType())) {
// Content-Length or Transfer-Encoding: chunked must be provided by a user-specified header when a Flowable<byte[]> is given for the body.
//noinspection ConstantConditions
request.withBody((Flowable<ByteBuffer>) bodyContentObject);
Expand Down Expand Up @@ -375,12 +374,12 @@ public Single<HttpResponse> apply(String responseBody) throws Exception {
}

/**
* @param entityTypeToken the RestResponse subtype to get a constructor for.
* @param entityType the RestResponse subtype to get a constructor for.
* @return a Constructor which produces an instance of a RestResponse subtype.
*/
@SuppressWarnings("unchecked")
public static Constructor<? extends RestResponse<?, ?>> getRestResponseConstructor(TypeToken entityTypeToken) {
Class<? extends RestResponse<?, ?>> rawEntityType = (Class<? extends RestResponse<?, ?>>) entityTypeToken.getRawType();
public Constructor<? extends RestResponse<?, ?>> getRestResponseConstructor(Type entityType) {
Class<? extends RestResponse<?, ?>> rawEntityType = (Class<? extends RestResponse<?, ?>>) TypeUtil.getRawClass(entityType);
try {
Constructor<? extends RestResponse<?, ?>> ctor = null;
for (Constructor<?> c : rawEntityType.getDeclaredConstructors()) {
Expand All @@ -404,22 +403,20 @@ public Single<HttpResponse> apply(String responseBody) throws Exception {
}

private Single<?> handleRestResponseReturnTypeAsync(HttpResponse response, SwaggerMethodParser methodParser, Type entityType) {
final TypeToken entityTypeToken = TypeToken.of(entityType);
final int responseStatusCode = response.statusCode();

try {
Single<?> asyncResult;
if (entityTypeToken.isSubtypeOf(RestResponse.class)) {
Constructor<? extends RestResponse<?, ?>> responseConstructor = getRestResponseConstructor(entityTypeToken);
if (TypeUtil.isTypeOrSubTypeOf(entityType, RestResponse.class)) {
Constructor<? extends RestResponse<?, ?>> responseConstructor = getRestResponseConstructor(entityType);

Type[] deserializedTypes = getTypeArguments(entityTypeToken.getSupertype(RestResponse.class).getType());
Type[] deserializedTypes = TypeUtil.getTypeArguments(TypeUtil.getSuperType(entityType, RestResponse.class));

HttpHeaders responseHeaders = response.headers();
Object deserializedHeaders = response.deserializedHeaders();

Type bodyType = deserializedTypes[1];
TypeToken bodyTypeToken = TypeToken.of(bodyType);
if (bodyTypeToken.isSubtypeOf(Void.class)) {
if (TypeUtil.isTypeOrSubTypeOf(bodyType, Void.class)) {
asyncResult = response.body().lastElement().ignoreElement()
.andThen(Single.just(responseConstructor.newInstance(response.request(), responseStatusCode, deserializedHeaders, responseHeaders.toMap(), null)));
} else {
Expand All @@ -431,7 +428,7 @@ private Single<?> handleRestResponseReturnTypeAsync(HttpResponse response, Swagg
}

Type headersType = deserializedTypes[0];
if (!response.isDecoded() && !TypeToken.of(headersType).isSubtypeOf(Void.class)) {
if (!response.isDecoded() && !TypeUtil.isTypeOrSubTypeOf(headersType, Void.class)) {
asyncResult = asyncResult.toCompletable().andThen(Single.error(new RestException(
"No deserialized headers were found. Please add a DecodingPolicyFactory to the HttpPipeline.",
response,
Expand All @@ -449,23 +446,22 @@ private Single<?> handleRestResponseReturnTypeAsync(HttpResponse response, Swagg
}

protected final Maybe<?> handleBodyReturnTypeAsync(final HttpResponse response, final SwaggerMethodParser methodParser, final Type entityType) {
final TypeToken entityTypeToken = TypeToken.of(entityType);
final int responseStatusCode = response.statusCode();
final HttpMethod httpMethod = methodParser.httpMethod();
final Type returnValueWireType = methodParser.returnValueWireType();

final Maybe<?> asyncResult;
if (httpMethod == HttpMethod.HEAD
&& (entityTypeToken.isSubtypeOf(Boolean.TYPE) || entityTypeToken.isSubtypeOf(Boolean.class))) {
&& (TypeUtil.isTypeOrSubTypeOf(entityType, Boolean.TYPE) || TypeUtil.isTypeOrSubTypeOf(entityType, Boolean.class))) {
boolean isSuccess = (responseStatusCode / 100) == 2;
asyncResult = Maybe.just(isSuccess);
} else if (entityTypeToken.isSubtypeOf(byte[].class)) {
} else if (TypeUtil.isTypeOrSubTypeOf(entityType, byte[].class)) {
Maybe<byte[]> responseBodyBytesAsync = response.bodyAsByteArray().toMaybe();
if (returnValueWireType == Base64Url.class) {
responseBodyBytesAsync = responseBodyBytesAsync.map(base64UrlBytes -> new Base64Url(base64UrlBytes).decodedBytes());
}
asyncResult = responseBodyBytesAsync;
} else if (FlowableUtil.isFlowableByteBuffer(entityTypeToken)) {
} else if (FlowableUtil.isFlowableByteBuffer(entityType)) {
asyncResult = Maybe.just(response.body());
} else if (!response.isDecoded()) {
asyncResult = Maybe.error(new RestException(
Expand Down Expand Up @@ -504,25 +500,23 @@ protected Object handleResumeOperation(HttpRequest httpRequest, OperationDescrip
public final Object handleRestReturnType(HttpRequest httpRequest, Single<HttpResponse> asyncHttpResponse, final SwaggerMethodParser methodParser, final Type returnType) {
Object result;

final TypeToken returnTypeToken = TypeToken.of(returnType);

final Single<HttpResponse> asyncExpectedResponse = ensureExpectedStatus(asyncHttpResponse, methodParser);

if (returnTypeToken.isSubtypeOf(Completable.class)) {
if (TypeUtil.isTypeOrSubTypeOf(returnType, Completable.class)) {
result = Completable.fromSingle(asyncExpectedResponse);
}
else if (returnTypeToken.isSubtypeOf(Single.class)) {
final Type singleTypeParam = getTypeArgument(returnType);
else if (TypeUtil.isTypeOrSubTypeOf(returnType, Single.class)) {
final Type singleTypeParam = TypeUtil.getTypeArgument(returnType);
result = asyncExpectedResponse.flatMap(response ->
handleRestResponseReturnTypeAsync(response, methodParser, singleTypeParam));
}
else if (returnTypeToken.isSubtypeOf(Observable.class)) {
else if (TypeUtil.isTypeOrSubTypeOf(returnType, Observable.class)) {
throw new InvalidReturnTypeException("RestProxy does not support swagger interface methods (such as " + methodParser.fullyQualifiedMethodName() + "()) with a return type of " + returnType.toString());
}
else if (FlowableUtil.isFlowableByteBuffer(returnTypeToken)) {
else if (FlowableUtil.isFlowableByteBuffer(returnType)) {
result = asyncExpectedResponse.flatMapPublisher(HttpResponse::body);
}
else if (returnTypeToken.isSubtypeOf(void.class) || returnTypeToken.isSubtypeOf(Void.class)) {
else if (TypeUtil.isTypeOrSubTypeOf(returnType, void.class) || TypeUtil.isTypeOrSubTypeOf(returnType, Void.class)) {
asyncExpectedResponse.blockingGet();
result = null;
} else {
Expand All @@ -537,14 +531,6 @@ else if (returnTypeToken.isSubtypeOf(void.class) || returnTypeToken.isSubtypeOf(
return result;
}

private static Type[] getTypeArguments(Type type) {
return ((ParameterizedType) type).getActualTypeArguments();
}

private static Type getTypeArgument(Type type) {
return getTypeArguments(type)[0];
}

/**
* Create an instance of the default serializer.
* @return the default serializer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@

package com.microsoft.rest.v2;

import com.google.common.util.concurrent.AbstractFuture;
import io.reactivex.Maybe;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;

import java.util.concurrent.CompletableFuture;

/**
* An instance of this class provides access to the underlying REST call invocation.
* This class wraps around the Retrofit Call object and allows updates to it in the
* progress of a long running operation or a paging operation.
*
* @param <T> the type of the returning object
*/
public class ServiceFuture<T> extends AbstractFuture<T> {
public class ServiceFuture<T> extends CompletableFuture<T> {
/**
* The Retrofit method invocation.
*/
Expand All @@ -47,15 +48,15 @@ public void accept(T t) {
if (callback != null) {
callback.success(t);
}
serviceFuture.set(t);
serviceFuture.complete(t);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
if (callback != null) {
callback.failure(throwable);
}
serviceFuture.setException(throwable);
serviceFuture.completeExceptionally(throwable);
}
});
return serviceFuture;
Expand All @@ -78,23 +79,23 @@ public void accept(T t) {
if (callback != null) {
callback.success(t);
}
serviceFuture.set(t);
serviceFuture.complete(t);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
if (callback != null) {
callback.failure(throwable);
}
serviceFuture.setException(throwable);
serviceFuture.completeExceptionally(throwable);
}
}, new Action() {
@Override
public void run() throws Exception {
if (callback != null) {
callback.success(null);
}
serviceFuture.set(null);
serviceFuture.complete(null);
}
});
return serviceFuture;
Expand All @@ -116,15 +117,15 @@ public void run() {
if (callback != null) {
callback.success(value);
}
serviceFuture.set(value);
serviceFuture.complete(value);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
if (callback != null) {
callback.failure(throwable);
}
serviceFuture.setException(throwable);
serviceFuture.completeExceptionally(throwable);
}
});
return serviceFuture;
Expand All @@ -141,17 +142,6 @@ protected void setSubscription(Disposable subscription) {
this.subscription = subscription;
}

/**
* Invoke this method to report completed, allowing
* {@link AbstractFuture#get()} to be unblocked.
*
* @param result the service response returned.
* @return true if successfully reported; false otherwise.
*/
public boolean success(T result) {
return set(result);
}

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
subscription.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@

import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.google.common.reflect.TypeToken;
import com.microsoft.rest.v2.annotations.BodyParam;
import com.microsoft.rest.v2.annotations.DELETE;
import com.microsoft.rest.v2.annotations.ExpectedResponses;
import com.microsoft.rest.v2.annotations.ReturnValueWireType;
import com.microsoft.rest.v2.annotations.UnexpectedResponseExceptionType;
import com.microsoft.rest.v2.annotations.GET;
import com.microsoft.rest.v2.annotations.HEAD;
import com.microsoft.rest.v2.annotations.HeaderParam;
Expand All @@ -24,10 +21,13 @@
import com.microsoft.rest.v2.annotations.PUT;
import com.microsoft.rest.v2.annotations.PathParam;
import com.microsoft.rest.v2.annotations.QueryParam;
import com.microsoft.rest.v2.annotations.ReturnValueWireType;
import com.microsoft.rest.v2.annotations.UnexpectedResponseExceptionType;
import com.microsoft.rest.v2.http.HttpHeader;
import com.microsoft.rest.v2.http.HttpHeaders;
import com.microsoft.rest.v2.http.HttpMethod;
import com.microsoft.rest.v2.protocol.SerializerAdapter;
import com.microsoft.rest.v2.util.TypeUtil;
import io.reactivex.Observable;
import io.reactivex.Single;

Expand Down Expand Up @@ -116,8 +116,7 @@ else if (swaggerMethod.isAnnotationPresent(PATCH.class)) {
this.returnValueWireType = returnValueWireType;
}
else {
final TypeToken wireTypeToken = TypeToken.of(returnValueWireType);
if (wireTypeToken.isSubtypeOf(List.class)) {
if (TypeUtil.isTypeOrSubTypeOf(returnValueWireType, List.class)) {
this.returnValueWireType = returnValueWireType.getGenericInterfaces()[0];
}
}
Expand Down Expand Up @@ -441,21 +440,19 @@ public Type returnValueWireType() {
public boolean expectsResponseBody() {
boolean result = true;

final TypeToken returnTypeToken = TypeToken.of(returnType);
if (returnTypeToken.isSubtypeOf(Void.class)) {
if (TypeUtil.isTypeOrSubTypeOf(returnType, Void.class)) {
result = false;
}
else if (returnTypeToken.isSubtypeOf(Single.class) || returnTypeToken.isSubtypeOf(Observable.class)) {
else if (TypeUtil.isTypeOrSubTypeOf(returnType, Single.class) || TypeUtil.isTypeOrSubTypeOf(returnType, Observable.class)) {
final ParameterizedType asyncReturnType = (ParameterizedType) returnType;
final Type syncReturnType = asyncReturnType.getActualTypeArguments()[0];
final TypeToken syncReturnTypeToken = TypeToken.of(syncReturnType);
if (syncReturnTypeToken.isSubtypeOf(Void.class)) {
if (TypeUtil.isTypeOrSubTypeOf(syncReturnType, Void.class)) {
result = false;
} else if (syncReturnTypeToken.isSubtypeOf(RestResponse.class)) {
result = restResponseTypeExpectsBody((ParameterizedType) syncReturnTypeToken.getSupertype(RestResponse.class).getType());
} else if (TypeUtil.isTypeOrSubTypeOf(syncReturnType, RestResponse.class)) {
result = restResponseTypeExpectsBody((ParameterizedType) TypeUtil.getSuperType(syncReturnType, RestResponse.class));
}
} else if (returnTypeToken.isSubtypeOf(RestResponse.class)) {
result = restResponseTypeExpectsBody((ParameterizedType) returnTypeToken.getSupertype(RestResponse.class).getType());
} else if (TypeUtil.isTypeOrSubTypeOf(returnType, RestResponse.class)) {
result = restResponseTypeExpectsBody((ParameterizedType) TypeUtil.getSuperType(returnType, RestResponse.class));
}

return result;
Expand Down
Loading

0 comments on commit 057546c

Please sign in to comment.