From 057546cd98d30fcc45c7fd5de1cdc5a2b247b044 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 23 Aug 2018 16:03:11 -0700 Subject: [PATCH] Guava gone (#477) * 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 --- client-runtime/pom.xml | 1 + .../java/com/microsoft/rest/v2/RestProxy.java | 54 +++--- .../com/microsoft/rest/v2/ServiceFuture.java | 32 ++-- .../rest/v2/SwaggerMethodParser.java | 25 ++- .../java/com/microsoft/rest/v2/Validator.java | 69 ++++++-- .../rest/v2/http/ConcurrentMultiHashMap.java | 14 +- .../microsoft/rest/v2/http/NettyClient.java | 30 ++-- .../rest/v2/protocol/HttpResponseDecoder.java | 157 ++++++++-------- .../rest/v2/protocol/SerializerAdapter.java | 6 - .../rest/v2/protocol/TypeFactory.java | 38 ---- .../v2/serializer/FlatteningDeserializer.java | 4 +- .../rest/v2/serializer/JacksonAdapter.java | 39 ++-- .../v2/serializer/JacksonTypeFactory.java | 65 ------- .../microsoft/rest/v2/util/FlowableUtil.java | 14 +- .../com/microsoft/rest/v2/util/TypeUtil.java | 167 ++++++++++++++++++ pom.xml | 22 +-- 16 files changed, 395 insertions(+), 342 deletions(-) delete mode 100644 client-runtime/src/main/java/com/microsoft/rest/v2/protocol/TypeFactory.java delete mode 100644 client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonTypeFactory.java create mode 100644 client-runtime/src/main/java/com/microsoft/rest/v2/util/TypeUtil.java diff --git a/client-runtime/pom.xml b/client-runtime/pom.xml index c2a0b53bcf45a..98e5fa17ca049 100644 --- a/client-runtime/pom.xml +++ b/client-runtime/pom.xml @@ -50,6 +50,7 @@ com.google.guava guava + 20.0 io.netty diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/RestProxy.java b/client-runtime/src/main/java/com/microsoft/rest/v2/RestProxy.java index 65d384e7ac14b..1492327ed162f 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/RestProxy.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/RestProxy.java @@ -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; @@ -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; @@ -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; @@ -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 is given for the body. //noinspection ConstantConditions request.withBody((Flowable) bodyContentObject); @@ -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 is given for the body. //noinspection ConstantConditions request.withBody((Flowable) bodyContentObject); @@ -375,12 +374,12 @@ public Single 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> getRestResponseConstructor(TypeToken entityTypeToken) { - Class> rawEntityType = (Class>) entityTypeToken.getRawType(); + public Constructor> getRestResponseConstructor(Type entityType) { + Class> rawEntityType = (Class>) TypeUtil.getRawClass(entityType); try { Constructor> ctor = null; for (Constructor c : rawEntityType.getDeclaredConstructors()) { @@ -404,22 +403,20 @@ public Single 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> responseConstructor = getRestResponseConstructor(entityTypeToken); + if (TypeUtil.isTypeOrSubTypeOf(entityType, RestResponse.class)) { + Constructor> 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 { @@ -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, @@ -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 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( @@ -504,25 +500,23 @@ protected Object handleResumeOperation(HttpRequest httpRequest, OperationDescrip public final Object handleRestReturnType(HttpRequest httpRequest, Single asyncHttpResponse, final SwaggerMethodParser methodParser, final Type returnType) { Object result; - final TypeToken returnTypeToken = TypeToken.of(returnType); - final Single 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 { @@ -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. diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/ServiceFuture.java b/client-runtime/src/main/java/com/microsoft/rest/v2/ServiceFuture.java index 7e24a2bd0fcf2..0e3bb42442431 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/ServiceFuture.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/ServiceFuture.java @@ -6,14 +6,15 @@ 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 @@ -21,7 +22,7 @@ * * @param the type of the returning object */ -public class ServiceFuture extends AbstractFuture { +public class ServiceFuture extends CompletableFuture { /** * The Retrofit method invocation. */ @@ -47,7 +48,7 @@ public void accept(T t) { if (callback != null) { callback.success(t); } - serviceFuture.set(t); + serviceFuture.complete(t); } }, new Consumer() { @Override @@ -55,7 +56,7 @@ public void accept(Throwable throwable) { if (callback != null) { callback.failure(throwable); } - serviceFuture.setException(throwable); + serviceFuture.completeExceptionally(throwable); } }); return serviceFuture; @@ -78,7 +79,7 @@ public void accept(T t) { if (callback != null) { callback.success(t); } - serviceFuture.set(t); + serviceFuture.complete(t); } }, new Consumer() { @Override @@ -86,7 +87,7 @@ public void accept(Throwable throwable) { if (callback != null) { callback.failure(throwable); } - serviceFuture.setException(throwable); + serviceFuture.completeExceptionally(throwable); } }, new Action() { @Override @@ -94,7 +95,7 @@ public void run() throws Exception { if (callback != null) { callback.success(null); } - serviceFuture.set(null); + serviceFuture.complete(null); } }); return serviceFuture; @@ -116,7 +117,7 @@ public void run() { if (callback != null) { callback.success(value); } - serviceFuture.set(value); + serviceFuture.complete(value); } }, new Consumer() { @Override @@ -124,7 +125,7 @@ public void accept(Throwable throwable) { if (callback != null) { callback.failure(throwable); } - serviceFuture.setException(throwable); + serviceFuture.completeExceptionally(throwable); } }); return serviceFuture; @@ -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(); diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/SwaggerMethodParser.java b/client-runtime/src/main/java/com/microsoft/rest/v2/SwaggerMethodParser.java index 9d7e84418a378..21711d0381c39 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/SwaggerMethodParser.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/SwaggerMethodParser.java @@ -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; @@ -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; @@ -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]; } } @@ -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; diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/Validator.java b/client-runtime/src/main/java/com/microsoft/rest/v2/Validator.java index 2e2ed4aba2cc7..02baa410a86b0 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/Validator.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/Validator.java @@ -7,8 +7,7 @@ package com.microsoft.rest.v2; import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.common.primitives.Primitives; -import com.google.common.reflect.TypeToken; +import com.microsoft.rest.v2.util.TypeUtil; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -40,23 +39,29 @@ public static void validate(Object parameter) { return; } - Class parameterType = parameter.getClass(); - TypeToken parameterToken = TypeToken.of(parameterType); - if (Primitives.isWrapperType(parameterType)) { - parameterToken = parameterToken.unwrap(); + Class type = parameter.getClass(); + if (type == Double.class + || type == Float.class + || type == Long.class + || type == Integer.class + || type == Short.class + || type == Character.class + || type == Byte.class + || type == Boolean.class) { + type = wrapperToPrimitive(type); } - if (parameterToken.isPrimitive() - || parameterType.isEnum() - || parameterType == Class.class - || parameterToken.isSupertypeOf(LocalDate.class) - || parameterToken.isSupertypeOf(OffsetDateTime.class) - || parameterToken.isSupertypeOf(String.class) - || parameterToken.isSupertypeOf(DateTimeRfc1123.class) - || parameterToken.isSupertypeOf(Duration.class)) { + if (type.isPrimitive() + || type.isEnum() + || type.isAssignableFrom(Class.class) + || type.isAssignableFrom(LocalDate.class) + || type.isAssignableFrom(OffsetDateTime.class) + || type.isAssignableFrom(String.class) + || type.isAssignableFrom(DateTimeRfc1123.class) + || type.isAssignableFrom(Duration.class)) { return; } - for (Class c : parameterToken.getTypes().classes().rawTypes()) { + for (Class c : TypeUtil.getAllClasses(type)) { // Ignore checks for Object type. if (c.isAssignableFrom(Object.class)) { continue; @@ -86,20 +91,20 @@ public static void validate(Object parameter) { } else { try { Class propertyType = property.getClass(); - if (TypeToken.of(List.class).isSupertypeOf(propertyType)) { + if (List.class.isAssignableFrom(propertyType)) { List items = (List) property; for (Object item : items) { Validator.validate(item); } } - else if (TypeToken.of(Map.class).isSupertypeOf(propertyType)) { + else if (Map.class.isAssignableFrom(propertyType)) { Map entries = (Map) property; for (Map.Entry entry : entries.entrySet()) { Validator.validate(entry.getKey()); Validator.validate(entry.getValue()); } } - else if (parameterType != propertyType) { + else if (type != propertyType) { Validator.validate(property); } } catch (IllegalArgumentException ex) { @@ -114,4 +119,32 @@ else if (parameterType != propertyType) { } } } + + private static Class wrapperToPrimitive(Class clazz) { + if (!clazz.isPrimitive()) { + return clazz; + } + + if (clazz == Integer.class) { + return Integer.TYPE; + } else if (clazz == Long.class) { + return Long.TYPE; + } else if (clazz == Boolean.class) { + return Boolean.TYPE; + } else if (clazz == Byte.class) { + return Byte.TYPE; + } else if (clazz == Character.class) { + return Character.TYPE; + } else if (clazz == Float.class) { + return Float.TYPE; + } else if (clazz == Double.class) { + return Double.TYPE; + } else if (clazz == Short.class) { + return Short.TYPE; + } else if (clazz == Void.class) { + return Void.TYPE; + } + + return clazz; + } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/http/ConcurrentMultiHashMap.java b/client-runtime/src/main/java/com/microsoft/rest/v2/http/ConcurrentMultiHashMap.java index aab7d101cda5f..ec14bcdfbd7bc 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/http/ConcurrentMultiHashMap.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/http/ConcurrentMultiHashMap.java @@ -6,9 +6,6 @@ package com.microsoft.rest.v2.http; -import com.google.common.base.Predicate; -import com.google.common.collect.Sets; - import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -127,12 +124,13 @@ public boolean containsKey(K key) { * @return the set of keys with which there are values associated */ public Set keys() { - return Sets.filter(data.keySet(), new Predicate() { - @Override - public boolean apply(K input) { - return data.get(input).size() > 0; + Set keys = new HashSet<>(); + for (K key : data.keySet()) { + if (data.get(key).size() > 0) { + keys.add(key); } - }); + } + return keys; } /** diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/http/NettyClient.java b/client-runtime/src/main/java/com/microsoft/rest/v2/http/NettyClient.java index 9a917751850c2..bd87698e42c4e 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/http/NettyClient.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/http/NettyClient.java @@ -6,22 +6,7 @@ package com.microsoft.rest.v2.http; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - import com.microsoft.rest.v2.util.FlowableUtil; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -54,9 +39,22 @@ import io.reactivex.internal.subscriptions.SubscriptionHelper; import io.reactivex.internal.util.BackpressureHelper; import io.reactivex.plugins.RxJavaPlugins; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import static com.microsoft.rest.v2.util.FlowableUtil.ensureLength; + /** * An HttpClient that is implemented using Netty. */ @@ -869,7 +867,7 @@ private static final class ChannelSubscription implements Subscription { @Override public void request(long n) { - Preconditions.checkArgument(n == 1, "requests must be one at a time!"); + assert n == 1 : "requests must be one at a time!"; Channel c = channel.get(); if (c != null) { c.read(); diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/HttpResponseDecoder.java b/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/HttpResponseDecoder.java index e15b5fd7ef77d..7c18fa5be07a9 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/HttpResponseDecoder.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/HttpResponseDecoder.java @@ -7,7 +7,6 @@ package com.microsoft.rest.v2.protocol; import com.fasterxml.jackson.core.JsonParseException; -import com.google.common.reflect.TypeToken; import com.microsoft.rest.v2.Base64Url; import com.microsoft.rest.v2.DateTimeRfc1123; import com.microsoft.rest.v2.RestException; @@ -20,6 +19,7 @@ import com.microsoft.rest.v2.http.HttpMethod; import com.microsoft.rest.v2.http.HttpResponse; import com.microsoft.rest.v2.util.FlowableUtil; +import com.microsoft.rest.v2.util.TypeUtil; import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Observable; @@ -70,13 +70,13 @@ public Single decode(final HttpResponse response) { final Type returnValueWireType = methodParser.returnValueWireType(); - final TypeToken entityTypeToken = getEntityType(); + final Type entityType = getEntityType(); boolean isSerializableBody = methodParser.httpMethod() != HttpMethod.HEAD - && !FlowableUtil.isFlowableByteBuffer(entityTypeToken) - && !entityTypeToken.isSubtypeOf(Completable.class) - && !entityTypeToken.isSubtypeOf(byte[].class) - && !entityTypeToken.isSubtypeOf(Void.TYPE) && !entityTypeToken.isSubtypeOf(Void.class); + && !FlowableUtil.isFlowableByteBuffer(entityType) + && !TypeUtil.isTypeOrSubTypeOf(entityType, Completable.class) + && !TypeUtil.isTypeOrSubTypeOf(entityType, byte[].class) + && !TypeUtil.isTypeOrSubTypeOf(entityType, Void.TYPE) && !TypeUtil.isTypeOrSubTypeOf(entityType, Void.class); int[] expectedStatuses = methodParser.expectedStatusCodes(); boolean isErrorStatus = true; @@ -116,7 +116,7 @@ public HttpResponse apply(String bodyString) throws Exception { @Override public HttpResponse apply(String bodyString) throws Exception { try { - Object body = deserializeBody(bodyString, getEntityType().getType(), returnValueWireType, SerializerEncoding.fromHeaders(response.headers())); + Object body = deserializeBody(bodyString, getEntityType(), returnValueWireType, SerializerEncoding.fromHeaders(response.headers())); return bufferedResponse .withDeserializedHeaders(deserializedHeaders) .withDeserializedBody(body); @@ -147,14 +147,6 @@ private Object deserializeBody(String value, Type resultType, Type wireType, Ser return result; } - private static Type[] getTypeArguments(Type type) { - return ((ParameterizedType) type).getActualTypeArguments(); - } - - private static Type getTypeArgument(Type type) { - return getTypeArguments(type)[0]; - } - private Type constructWireResponseType(Type resultType, Type wireType) { Type wireResponseType = resultType; @@ -172,21 +164,20 @@ else if (wireType == UnixTime.class) { } } else { - final TypeToken resultTypeToken = TypeToken.of(resultType); - if (resultTypeToken.isSubtypeOf(List.class)) { - final Type resultElementType = getTypeArgument(resultType); + if (TypeUtil.isTypeOrSubTypeOf(resultType, List.class)) { + final Type resultElementType = TypeUtil.getTypeArgument(resultType); final Type wireResponseElementType = constructWireResponseType(resultElementType, wireType); - final TypeFactory typeFactory = serializer.getTypeFactory(); - wireResponseType = typeFactory.create((ParameterizedType) resultType, wireResponseElementType); + wireResponseType = TypeUtil.createParameterizedType( + (Class) ((ParameterizedType) resultType).getRawType(), wireResponseElementType); } - else if (resultTypeToken.isSubtypeOf(Map.class) || resultTypeToken.isSubtypeOf(RestResponse.class)) { - Type[] typeArguments = getTypeArguments(resultType); + else if (TypeUtil.isTypeOrSubTypeOf(resultType, Map.class) || TypeUtil.isTypeOrSubTypeOf(resultType, RestResponse.class)) { + Type[] typeArguments = TypeUtil.getTypeArguments(resultType); final Type resultValueType = typeArguments[1]; final Type wireResponseValueType = constructWireResponseType(resultValueType, wireType); - final TypeFactory typeFactory = serializer.getTypeFactory(); - wireResponseType = typeFactory.create((ParameterizedType) resultType, new Type[] {typeArguments[0], wireResponseValueType}); + wireResponseType = TypeUtil.createParameterizedType( + (Class) ((ParameterizedType) resultType).getRawType(), typeArguments[0], wireResponseValueType); } } return wireResponseType; @@ -207,9 +198,8 @@ private Object convertToResultType(Object wireResponse, Type resultType, Type wi result = ((UnixTime) wireResponse).dateTime(); } } else { - final TypeToken resultTypeToken = TypeToken.of(resultType); - if (resultTypeToken.isSubtypeOf(List.class)) { - final Type resultElementType = getTypeArgument(resultType); + if (TypeUtil.isTypeOrSubTypeOf(resultType, List.class)) { + final Type resultElementType = TypeUtil.getTypeArgument(resultType); final List wireResponseList = (List) wireResponse; @@ -224,8 +214,8 @@ private Object convertToResultType(Object wireResponse, Type resultType, Type wi result = wireResponseList; } - else if (resultTypeToken.isSubtypeOf(Map.class)) { - final Type resultValueType = getTypeArguments(resultType)[1]; + else if (TypeUtil.isTypeOrSubTypeOf(resultType, Map.class)) { + final Type resultValueType = TypeUtil.getTypeArguments(resultType)[1]; final Map wireResponseMap = (Map) wireResponse; @@ -237,12 +227,12 @@ else if (resultTypeToken.isSubtypeOf(Map.class)) { wireResponseMap.put(wireResponseKey, resultValue); } } - } else if (resultTypeToken.isSubtypeOf(RestResponse.class)) { + } else if (TypeUtil.isTypeOrSubTypeOf(resultType, RestResponse.class)) { RestResponse restResponse = (RestResponse) wireResponse; Object wireResponseBody = restResponse.body(); // FIXME: RestProxy is always in charge of creating RestResponse--so this doesn't seem right - Object resultBody = convertToResultType(wireResponseBody, getTypeArguments(resultType)[1], wireType); + Object resultBody = convertToResultType(wireResponseBody, TypeUtil.getTypeArguments(resultType)[1], wireType); if (wireResponseBody != resultBody) { result = new RestResponse<>(restResponse.request(), restResponse.statusCode(), restResponse.headers(), restResponse.rawHeaders(), resultBody); } else { @@ -255,22 +245,22 @@ else if (resultTypeToken.isSubtypeOf(Map.class)) { return result; } - private TypeToken getEntityType() { - TypeToken token = TypeToken.of(methodParser.returnType()); + private Type getEntityType() { + Type token = methodParser.returnType(); - if (token.isSubtypeOf(Single.class) || token.isSubtypeOf(Maybe.class) || token.isSubtypeOf(Observable.class)) { - token = TypeToken.of(getTypeArgument(token.getType())); + if (TypeUtil.isTypeOrSubTypeOf(token, Single.class) || TypeUtil.isTypeOrSubTypeOf(token, Maybe.class) || TypeUtil.isTypeOrSubTypeOf(token, Observable.class)) { + token = TypeUtil.getTypeArgument(token); } - if (token.isSubtypeOf(RestResponse.class)) { - token = token.getSupertype(RestResponse.class); - token = TypeToken.of(getTypeArguments(token.getType())[1]); + if (TypeUtil.isTypeOrSubTypeOf(token, RestResponse.class)) { + token = TypeUtil.getSuperType(token, RestResponse.class); + token = TypeUtil.getTypeArguments(token)[1]; } // TODO: unwrap OperationStatus a different way? try { - if (token.isSubtypeOf(Class.forName("com.microsoft.azure.v2.OperationStatus"))) { - token = TypeToken.of(getTypeArgument(token.getType())); + if (TypeUtil.isTypeOrSubTypeOf(token, Class.forName("com.microsoft.azure.v2.OperationStatus"))) { + token = TypeUtil.getTypeArgument(token); } } catch (Exception ignored) { } @@ -279,68 +269,67 @@ private TypeToken getEntityType() { } private Type getHeadersType() { - TypeToken token = TypeToken.of(methodParser.returnType()); + Type token = methodParser.returnType(); Type headersType = null; - if (token.isSubtypeOf(Single.class)) { - token = TypeToken.of(getTypeArgument(token.getType())); + if (TypeUtil.isTypeOrSubTypeOf(token, Single.class)) { + token = TypeUtil.getTypeArgument(token); } - if (token.isSubtypeOf(RestResponse.class)) { - token = token.getSupertype(RestResponse.class); - headersType = getTypeArguments(token.getType())[0]; + if (TypeUtil.isTypeOrSubTypeOf(token, RestResponse.class)) { + headersType = TypeUtil.getTypeArguments(TypeUtil.getSuperType(token, RestResponse.class))[0]; } return headersType; } private Object deserializeHeaders(HttpHeaders headers) throws IOException { - final Type deserializedHeadersType = getHeadersType(); - if (deserializedHeadersType == null) { - return null; - } else { - final String headersJsonString = serializer.serialize(headers, SerializerEncoding.JSON); - Object deserializedHeaders = serializer.deserialize(headersJsonString, deserializedHeadersType, SerializerEncoding.JSON); - - final Class deserializedHeadersClass = TypeToken.of(deserializedHeadersType).getRawType(); - final Field[] declaredFields = deserializedHeadersClass.getDeclaredFields(); - for (final Field declaredField : declaredFields) { - if (declaredField.isAnnotationPresent(HeaderCollection.class)) { - final Type declaredFieldType = declaredField.getGenericType(); - if (TypeToken.of(declaredField.getType()).isSubtypeOf(Map.class)) { - final Type[] mapTypeArguments = getTypeArguments(declaredFieldType); - if (mapTypeArguments.length == 2 && mapTypeArguments[0] == String.class && mapTypeArguments[1] == String.class) { - final HeaderCollection headerCollectionAnnotation = declaredField.getAnnotation(HeaderCollection.class); - final String headerCollectionPrefix = headerCollectionAnnotation.value().toLowerCase(); - final int headerCollectionPrefixLength = headerCollectionPrefix.length(); - if (headerCollectionPrefixLength > 0) { - final Map headerCollection = new HashMap<>(); - for (final HttpHeader header : headers) { - final String headerName = header.name(); - if (headerName.toLowerCase().startsWith(headerCollectionPrefix)) { - headerCollection.put(headerName.substring(headerCollectionPrefixLength), header.value()); - } + final Type deserializedHeadersType = getHeadersType(); + if (deserializedHeadersType == null) { + return null; + } else { + final String headersJsonString = serializer.serialize(headers, SerializerEncoding.JSON); + Object deserializedHeaders = serializer.deserialize(headersJsonString, deserializedHeadersType, SerializerEncoding.JSON); + + final Class deserializedHeadersClass = TypeUtil.getRawClass(deserializedHeadersType); + final Field[] declaredFields = deserializedHeadersClass.getDeclaredFields(); + for (final Field declaredField : declaredFields) { + if (declaredField.isAnnotationPresent(HeaderCollection.class)) { + final Type declaredFieldType = declaredField.getGenericType(); + if (TypeUtil.isTypeOrSubTypeOf(declaredField.getType(), Map.class)) { + final Type[] mapTypeArguments = TypeUtil.getTypeArguments(declaredFieldType); + if (mapTypeArguments.length == 2 && mapTypeArguments[0] == String.class && mapTypeArguments[1] == String.class) { + final HeaderCollection headerCollectionAnnotation = declaredField.getAnnotation(HeaderCollection.class); + final String headerCollectionPrefix = headerCollectionAnnotation.value().toLowerCase(); + final int headerCollectionPrefixLength = headerCollectionPrefix.length(); + if (headerCollectionPrefixLength > 0) { + final Map headerCollection = new HashMap<>(); + for (final HttpHeader header : headers) { + final String headerName = header.name(); + if (headerName.toLowerCase().startsWith(headerCollectionPrefix)) { + headerCollection.put(headerName.substring(headerCollectionPrefixLength), header.value()); } + } - final boolean declaredFieldAccessibleBackup = declaredField.isAccessible(); - try { - if (!declaredFieldAccessibleBackup) { - declaredField.setAccessible(true); - } - declaredField.set(deserializedHeaders, headerCollection); - } catch (IllegalAccessException ignored) { - } finally { - if (!declaredFieldAccessibleBackup) { - declaredField.setAccessible(declaredFieldAccessibleBackup); - } + final boolean declaredFieldAccessibleBackup = declaredField.isAccessible(); + try { + if (!declaredFieldAccessibleBackup) { + declaredField.setAccessible(true); + } + declaredField.set(deserializedHeaders, headerCollection); + } catch (IllegalAccessException ignored) { + } finally { + if (!declaredFieldAccessibleBackup) { + declaredField.setAccessible(declaredFieldAccessibleBackup); } } } } } } - - return deserializedHeaders; } + + return deserializedHeaders; + } } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/SerializerAdapter.java b/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/SerializerAdapter.java index f450ba9fdde38..e3c968853185f 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/SerializerAdapter.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/SerializerAdapter.java @@ -92,10 +92,4 @@ public interface SerializerAdapter { * @throws IOException exception in deserialization */ U deserialize(String value, Type type, SerializerEncoding encoding) throws IOException; - - /** - * Get the TypeFactory for this SerializerAdapter. - * @return The TypeFactory for this SerializerAdapter. - */ - TypeFactory getTypeFactory(); } diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/TypeFactory.java b/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/TypeFactory.java deleted file mode 100644 index bb6053fa54aa1..0000000000000 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/protocol/TypeFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - */ - -package com.microsoft.rest.v2.protocol; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - * A factory interface that can be used to create Types that can be used with a SerializerAdapter. - */ -public interface TypeFactory { - /** - * Create a SerializerAdapter-specific Type for the provided Type. - * @param type The type. - * @return The SerializerAdapter-specific Type. - */ - Type create(Type type); - - /** - * Create a SerializerAdapter-specific parametric Type for the provided Types. - * @param baseType The base type of the resulting parametric type. - * @param genericType The type argument for the resulting parametric type. - * @return The SerializerAdapter-specific parametric Type. - */ - Type create(ParameterizedType baseType, Type genericType); - - /** - * Create a SerializerAdapter-specific parametric Type for the provided Types. - * @param baseType The base type of the resulting parametric type. - * @param genericTypes The type arguments for the resulting parametric type. - * @return The SerializerAdapter-specific parametric Type. - */ - Type create(ParameterizedType baseType, Type[] genericTypes); -} diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/FlatteningDeserializer.java b/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/FlatteningDeserializer.java index 051bd3b45d008..f5c6b3db8c7a7 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/FlatteningDeserializer.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/FlatteningDeserializer.java @@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.reflect.TypeToken; +import com.microsoft.rest.v2.util.TypeUtil; import java.io.IOException; import java.lang.reflect.Field; @@ -80,7 +80,7 @@ public JsonDeserializer modifyDeserializer(DeserializationConfig config, Bean public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { JsonNode root = mapper.readTree(jp); final Class tClass = this.defaultDeserializer.handledType(); - for (Class c : TypeToken.of(tClass).getTypes().classes().rawTypes()) { + for (Class c : TypeUtil.getAllClasses(tClass)) { // Ignore checks for Object type. if (c.isAssignableFrom(Object.class)) { continue; diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonAdapter.java b/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonAdapter.java index 4c567b0f62045..8bcde813bb478 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonAdapter.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonAdapter.java @@ -15,14 +15,13 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.google.common.base.CharMatcher; -import com.google.common.base.Joiner; import com.microsoft.rest.v2.CollectionFormat; import com.microsoft.rest.v2.protocol.SerializerAdapter; import com.microsoft.rest.v2.protocol.SerializerEncoding; import java.io.IOException; import java.io.StringWriter; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -96,7 +95,7 @@ public String serializeRaw(Object object) { return null; } try { - return CharMatcher.is('"').trimFrom(serialize(object)); + return serialize(object).replaceAll("^\"*", "").replaceAll("\"*$", ""); } catch (IOException ex) { return null; } @@ -112,12 +111,7 @@ public String serializeList(List list, CollectionFormat format) { String raw = serializeRaw(element); serialized.add(raw != null ? raw : ""); } - return Joiner.on(format.getDelimiter()).join(serialized); - } - - @Override - public JacksonTypeFactory getTypeFactory() { - return new JacksonTypeFactory(mapper.getTypeFactory()); + return String.join(format.getDelimiter(), serialized); } @Override @@ -127,8 +121,7 @@ public T deserialize(String value, final Type type, SerializerEncoding encod return null; } - final JacksonTypeFactory typeFactory = getTypeFactory(); - final JavaType javaType = typeFactory.create(type); + final JavaType javaType = createJavaType(type); if (encoding == SerializerEncoding.XML) { return (T) xmlMapper.readValue(value, javaType); } else { @@ -168,4 +161,28 @@ private static T initializeObjectMapper(T mapper) { .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)); return mapper; } + + private JavaType createJavaType(Type type) { + JavaType result; + if (type == null) { + result = null; + } + else if (type instanceof JavaType) { + result = (JavaType) type; + } + else if (type instanceof ParameterizedType) { + final ParameterizedType parameterizedType = (ParameterizedType) type; + final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + JavaType[] javaTypeArguments = new JavaType[actualTypeArguments.length]; + for (int i = 0; i != actualTypeArguments.length; i++) { + javaTypeArguments[i] = createJavaType(actualTypeArguments[i]); + } + result = mapper.getTypeFactory().constructParametricType((Class) parameterizedType.getRawType(), javaTypeArguments); + } + else { + result = mapper.getTypeFactory().constructType(type); + } + return result; + } + } diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonTypeFactory.java b/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonTypeFactory.java deleted file mode 100644 index 33fb1a2eecc48..0000000000000 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/serializer/JacksonTypeFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - */ - -package com.microsoft.rest.v2.serializer; - -import com.fasterxml.jackson.databind.JavaType; -import com.microsoft.rest.v2.protocol.TypeFactory; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - * A TypeFactory that creates Jackson-compatible JavaType types. - */ -public class JacksonTypeFactory implements TypeFactory { - private final com.fasterxml.jackson.databind.type.TypeFactory typeFactory; - - /** - * Create a new JacksonTypeFactory. - * @param typeFactory The internal Jackson-specific TypeFactory that will be used. - */ - public JacksonTypeFactory(com.fasterxml.jackson.databind.type.TypeFactory typeFactory) { - this.typeFactory = typeFactory; - } - - @Override - public JavaType create(Type type) { - JavaType result; - if (type == null) { - result = null; - } - else if (type instanceof JavaType) { - result = (JavaType) type; - } - else if (type instanceof ParameterizedType) { - final ParameterizedType parameterizedType = (ParameterizedType) type; - final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - result = create(parameterizedType, actualTypeArguments); - } - else { - result = typeFactory.constructType(type); - } - return result; - } - - @Override - public JavaType create(ParameterizedType baseType, Type genericType) { - return create(baseType, new Type[]{genericType}); - } - - @Override - public JavaType create(ParameterizedType baseType, Type[] genericTypes) { - final Class rawType = (Class) baseType.getRawType(); - - final JavaType[] genericJavaTypes = new JavaType[genericTypes.length]; - for (int i = 0; i < genericJavaTypes.length; ++i) { - genericJavaTypes[i] = create(genericTypes[i]); - } - - return typeFactory.constructParametricType(rawType, genericJavaTypes); - } -} diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/util/FlowableUtil.java b/client-runtime/src/main/java/com/microsoft/rest/v2/util/FlowableUtil.java index bac2e7fc4ca16..762f0a8c5988f 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/v2/util/FlowableUtil.java +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/util/FlowableUtil.java @@ -6,8 +6,6 @@ package com.microsoft.rest.v2.util; -import com.google.common.reflect.TypeToken; - import com.microsoft.rest.v2.http.UnexpectedLengthException; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -23,7 +21,6 @@ import org.reactivestreams.Subscription; import java.io.IOException; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; @@ -39,14 +36,13 @@ public final class FlowableUtil { /** * Checks if a type is Flowable<ByteBuffer>. * - * @param entityTypeToken the type to check + * @param entityType the type to check * @return whether the type represents a Flowable that emits byte arrays */ - public static boolean isFlowableByteBuffer(TypeToken entityTypeToken) { - if (entityTypeToken.isSubtypeOf(Flowable.class)) { - final Type innerType = ((ParameterizedType) entityTypeToken.getType()).getActualTypeArguments()[0]; - final TypeToken innerTypeToken = TypeToken.of(innerType); - if (innerTypeToken.isSubtypeOf(ByteBuffer.class)) { + public static boolean isFlowableByteBuffer(Type entityType) { + if (TypeUtil.isTypeOrSubTypeOf(entityType, Flowable.class)) { + final Type innerType = TypeUtil.getTypeArguments(entityType)[0]; + if (TypeUtil.isTypeOrSubTypeOf(innerType, ByteBuffer.class)) { return true; } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/v2/util/TypeUtil.java b/client-runtime/src/main/java/com/microsoft/rest/v2/util/TypeUtil.java new file mode 100644 index 0000000000000..06297dfbbadc1 --- /dev/null +++ b/client-runtime/src/main/java/com/microsoft/rest/v2/util/TypeUtil.java @@ -0,0 +1,167 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + */ + +package com.microsoft.rest.v2.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Contains utilities for dealing with types. + */ +public class TypeUtil { + /** + * Find all super classes including this class itself. + * @param clazz the raw class to find super types for + * @return the list of super classes + */ + public static List> getAllClasses(Class clazz) { + List> types = new ArrayList<>(); + while (clazz != null) { + types.add(clazz); + clazz = clazz.getSuperclass(); + } + return types; + } + + /** + * Get the generic arguments for a type. + * @param type the type to get arguments + * @return the generic arguments, null if type is not parametrized + */ + public static Type[] getTypeArguments(Type type) { + if (!(type instanceof ParameterizedType)) { + return null; + } + return ((ParameterizedType) type).getActualTypeArguments(); + } + + /** + * Get the generic argument, or the first if the type has more than one. + * @param type the type to get arguments + * @return the generic argument, null if type is not parametrized + */ + public static Type getTypeArgument(Type type) { + if (!(type instanceof ParameterizedType)) { + return null; + } + return ((ParameterizedType) type).getActualTypeArguments()[0]; + } + + /** + * Get the raw class for a given type. + * @param type the input type + * @return the raw class + */ + public static Class getRawClass(Type type) { + if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getRawType(); + } else { + return (Class) type; + } + } + + /** + * Get the super type for a given type. + * @param type the input type + * @return the direct super type + */ + public static Type getSuperType(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Type genericSuperClass = ((Class) parameterizedType.getRawType()).getGenericSuperclass(); + if (genericSuperClass instanceof ParameterizedType) { + /* + * Find erased generic types for the super class and replace + * with actual type arguments from the parametrized type + */ + Type[] superTypeArguments = getTypeArguments(genericSuperClass); + List typeParameters = Arrays.asList(((Class) parameterizedType.getRawType()).getTypeParameters()); + int j = 0; + for (int i = 0; i != superTypeArguments.length; i++) { + if (typeParameters.contains(superTypeArguments[i])) { + superTypeArguments[i] = parameterizedType.getActualTypeArguments()[j++]; + } + } + return new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return superTypeArguments; + } + + @Override + public Type getRawType() { + return ((ParameterizedType) genericSuperClass).getRawType(); + } + + @Override + public Type getOwnerType() { + return null; + } + }; + } else { + return genericSuperClass; + } + } else { + return ((Class) type).getGenericSuperclass(); + } + } + + /** + * Get the super type for a type in its super type chain, which has + * a raw class that matches the specified class. + * @param subType the sub type to find super type for + * @param rawSuperType the raw class for the super type + * @return the super type that matches the requirement + */ + public static Type getSuperType(Type subType, Class rawSuperType) { + while (subType != null && getRawClass(subType) != rawSuperType) { + subType = getSuperType(subType); + } + return subType; + } + + /** + * Determines if a type is the same or a subtype for another type. + * @param subType the supposed sub type + * @param superType the supposed super type + * @return true if the first type is the same or a subtype for the second type + */ + public static boolean isTypeOrSubTypeOf(Type subType, Type superType) { + Class sub = getRawClass(subType); + Class sup = getRawClass(superType); + + return sup.isAssignableFrom(sub); + } + + /** + * Create a parametrized type from a raw class and its type arguments. + * @param rawClass the raw class to construct the parametrized type + * @param genericTypes the generic arguments + * @return the parametrized type + */ + public static ParameterizedType createParameterizedType(Class rawClass, Type... genericTypes) { + return new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return genericTypes; + } + + @Override + public Type getRawType() { + return rawClass; + } + + @Override + public Type getOwnerType() { + return null; + } + }; + } +} diff --git a/pom.xml b/pom.xml index e10084da32053..a2956839fc05e 100644 --- a/pom.xml +++ b/pom.xml @@ -55,11 +55,6 @@ - - com.google.guava - guava - 20.0 - com.fasterxml.jackson.datatype jackson-datatype-jsr310 @@ -70,16 +65,6 @@ jackson-dataformat-xml ${jackson.version} - - com.microsoft.azure - adal4j - 1.1.2 - - - com.microsoft.aad - adal - 1.1.11 - io.reactivex.rxjava2 rxjava @@ -93,7 +78,7 @@ com.microsoft.azure azure-annotations - 1.2.0 + 1.7.0 io.netty @@ -115,6 +100,11 @@ netty-codec-http ${netty.version} + + com.microsoft.azure + adal4j + 1.6.1 + org.slf4j