Skip to content

Commit 7968850

Browse files
authored
Added returnTypeDecodeable and responseEagerlyRead to SwaggerMethodParser (Azure#30100)
Added returnTypeDecodeable and responseEagerlyRead to SwaggerMethodParser
1 parent 2c75103 commit 7968850

File tree

9 files changed

+427
-360
lines changed

9 files changed

+427
-360
lines changed

sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/AsyncRestProxy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ private Object handleRestReturnType(final Mono<HttpResponseDecoder.HttpDecodedRe
208208
// ProxyMethod ReturnType: Mono<Void>
209209
result = asyncExpectedResponse.doOnNext(HttpResponseDecoder.HttpDecodedResponse::close).then();
210210
} else {
211-
// ProxyMethod ReturnType: Mono<? extends RestResponseBase<?, ?>>
211+
// ProxyMethod ReturnType: Mono<? extends ResponseBase<?, ?>>
212212
result = asyncExpectedResponse.flatMap(response ->
213213
handleRestResponseReturnType(response, methodParser, monoTypeParam));
214214
}

sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/RestProxyBase.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
import com.azure.core.exception.ResourceModifiedException;
1111
import com.azure.core.exception.ResourceNotFoundException;
1212
import com.azure.core.exception.TooManyRedirectsException;
13+
import com.azure.core.http.ContentType;
1314
import com.azure.core.http.HttpHeaders;
1415
import com.azure.core.http.HttpPipeline;
16+
import com.azure.core.http.HttpPipelineBuilder;
1517
import com.azure.core.http.HttpRequest;
1618
import com.azure.core.http.HttpResponse;
17-
import com.azure.core.http.HttpPipelineBuilder;
18-
import com.azure.core.http.ContentType;
1919
import com.azure.core.http.policy.CookiePolicy;
2020
import com.azure.core.http.policy.HttpPipelinePolicy;
2121
import com.azure.core.http.policy.RetryPolicy;
@@ -51,8 +51,6 @@
5151
import java.util.List;
5252
import java.util.function.Consumer;
5353

54-
import static com.azure.core.implementation.serializer.HttpResponseBodyDecoder.shouldEagerlyReadResponse;
55-
5654
public abstract class RestProxyBase {
5755
static final String MUST_IMPLEMENT_PAGE_ERROR =
5856
"Unable to create PagedResponse<T>. Body must be of a type that implements: " + Page.class;
@@ -95,8 +93,9 @@ public SwaggerMethodParser getMethodParser(Method method) {
9593
return interfaceParser.getMethodParser(method);
9694
}
9795

98-
public final Object invoke(Object proxy, final Method method, RequestOptions options, EnumSet<ErrorOptions> errorOptions,
99-
Consumer<HttpRequest> requestCallback, SwaggerMethodParser methodParser, boolean isAsync, Object[] args) {
96+
public final Object invoke(Object proxy, final Method method, RequestOptions options,
97+
EnumSet<ErrorOptions> errorOptions, Consumer<HttpRequest> requestCallback, SwaggerMethodParser methodParser,
98+
boolean isAsync, Object[] args) {
10099
RestProxyUtils.validateResumeOperationIsNotPresent(method);
101100

102101
try {
@@ -106,7 +105,7 @@ public final Object invoke(Object proxy, final Method method, RequestOptions opt
106105
context = RestProxyUtils.mergeRequestOptionsContext(context, options);
107106

108107
context = context.addData("caller-method", methodParser.getFullyQualifiedMethodName())
109-
.addData("azure-eagerly-read-response", shouldEagerlyReadResponse(methodParser.getReturnType()));
108+
.addData("azure-eagerly-read-response", methodParser.isResponseEagerlyRead());
110109

111110

112111
return invoke(proxy, method, options, errorOptions != null ? errorOptions : null,

sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/SwaggerMethodParser.java

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@
2727
import com.azure.core.http.HttpMethod;
2828
import com.azure.core.http.rest.Page;
2929
import com.azure.core.http.rest.RequestOptions;
30+
import com.azure.core.http.rest.Response;
31+
import com.azure.core.http.rest.ResponseBase;
3032
import com.azure.core.http.rest.RestProxy;
3133
import com.azure.core.http.rest.StreamResponse;
3234
import com.azure.core.implementation.TypeUtil;
3335
import com.azure.core.implementation.UnixTime;
3436
import com.azure.core.implementation.http.UnexpectedExceptionInformation;
3537
import com.azure.core.implementation.serializer.HttpResponseDecodeData;
3638
import com.azure.core.util.Base64Url;
39+
import com.azure.core.util.BinaryData;
3740
import com.azure.core.util.Context;
3841
import com.azure.core.util.CoreUtils;
3942
import com.azure.core.util.DateTimeRfc1123;
@@ -44,19 +47,25 @@
4447
import reactor.core.publisher.Flux;
4548
import reactor.core.publisher.Mono;
4649

50+
import java.io.InputStream;
4751
import java.lang.annotation.Annotation;
4852
import java.lang.reflect.Method;
4953
import java.lang.reflect.Type;
54+
import java.nio.ByteBuffer;
5055
import java.util.ArrayList;
5156
import java.util.Arrays;
5257
import java.util.BitSet;
5358
import java.util.HashMap;
5459
import java.util.List;
5560
import java.util.Map;
5661
import java.util.Objects;
62+
import java.util.function.Predicate;
5763
import java.util.regex.Pattern;
5864
import java.util.stream.Collectors;
5965

66+
import static com.azure.core.implementation.TypeUtil.getRawClass;
67+
import static com.azure.core.implementation.TypeUtil.typeImplementsInterface;
68+
6069
/**
6170
* This class contains the metadata of a {@link Method} contained in a Swagger interface used to make REST API calls in
6271
* {@link RestProxy}.
@@ -93,6 +102,8 @@ public class SwaggerMethodParser implements HttpResponseDecodeData {
93102
private final int requestOptionsPosition;
94103
private final boolean isReactive;
95104
private final boolean isStreamResponse;
105+
private final boolean returnTypeDecodeable;
106+
private final boolean responseEagerlyRead;
96107

97108
private Map<Integer, UnexpectedExceptionInformation> exceptionMapping;
98109
private UnexpectedExceptionInformation defaultException;
@@ -265,6 +276,10 @@ public SwaggerMethodParser(Method swaggerMethod, String rawHost, SerializerAdapt
265276
}
266277
this.contextPosition = contextPosition;
267278
this.requestOptionsPosition = requestOptionsPosition;
279+
280+
Type unwrappedReturnType = unwrapReturnType(returnType);
281+
this.returnTypeDecodeable = isReturnTypeDecodeable(unwrappedReturnType);
282+
this.responseEagerlyRead = isResponseEagerlyRead(unwrappedReturnType);
268283
}
269284

270285
/**
@@ -649,4 +664,90 @@ boolean isStreamResponseType(Type type) {
649664
public boolean isStreamResponse() {
650665
return isStreamResponse;
651666
}
667+
668+
@Override
669+
public boolean isReturnTypeDecodeable() {
670+
return returnTypeDecodeable;
671+
}
672+
673+
@Override
674+
public boolean isResponseEagerlyRead() {
675+
return responseEagerlyRead;
676+
}
677+
678+
static boolean isReturnTypeDecodeable(Type unwrappedReturnType) {
679+
if (unwrappedReturnType == null) {
680+
return false;
681+
}
682+
683+
return !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, BinaryData.class)
684+
&& !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, byte[].class)
685+
&& !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, ByteBuffer.class)
686+
&& !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, InputStream.class)
687+
&& !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, Void.TYPE)
688+
&& !TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, Void.class);
689+
}
690+
691+
static boolean isResponseEagerlyRead(Type unwrappedReturnType) {
692+
if (unwrappedReturnType == null) {
693+
return false;
694+
}
695+
696+
return isReturnTypeDecodeable(unwrappedReturnType)
697+
|| TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, Void.TYPE)
698+
|| TypeUtil.isTypeOrSubTypeOf(unwrappedReturnType, Void.class);
699+
}
700+
701+
static Type unwrapReturnType(Type returnType) {
702+
if (returnType == null) {
703+
return null;
704+
}
705+
706+
// First check if the return type is assignable, is a sub-type, to ResponseBase.
707+
// If it is begin walking up the super type hierarchy until ResponseBase is the raw type.
708+
// Then unwrap the second generic type (body type).
709+
if (TypeUtil.isTypeOrSubTypeOf(returnType, ResponseBase.class)) {
710+
returnType = walkSuperTypesUntil(returnType, type -> getRawClass(type) == ResponseBase.class);
711+
712+
return unwrapReturnType(TypeUtil.getTypeArguments(returnType)[1]);
713+
}
714+
715+
// Then, like ResponseBase, check if the return type is assignable to Response.
716+
// If it is begin walking up the super type hierarchy until the raw type implements Response.
717+
// Then unwrap its only generic type.
718+
if (TypeUtil.isTypeOrSubTypeOf(returnType, Response.class)) {
719+
// Handling for Response is slightly different as it is an interface unlike ResponseBase which is a class.
720+
// The super class hierarchy needs be walked until the super class itself implements Response.
721+
returnType = walkSuperTypesUntil(returnType, type -> typeImplementsInterface(type, Response.class));
722+
723+
return unwrapReturnType(TypeUtil.getTypeArgument(returnType));
724+
}
725+
726+
// Then check if the return type is a Mono or Flux and unwrap its only generic type.
727+
if (TypeUtil.isTypeOrSubTypeOf(returnType, Mono.class)) {
728+
returnType = walkSuperTypesUntil(returnType, type -> getRawClass(type) == Mono.class);
729+
730+
return unwrapReturnType(TypeUtil.getTypeArgument(returnType));
731+
}
732+
733+
if (TypeUtil.isTypeOrSubTypeOf(returnType, Flux.class)) {
734+
returnType = walkSuperTypesUntil(returnType, type -> getRawClass(type) == Flux.class);
735+
736+
return unwrapReturnType(TypeUtil.getTypeArgument(returnType));
737+
}
738+
739+
// Finally, there is no more unwrapping to perform and return the type as-is.
740+
return returnType;
741+
}
742+
743+
/*
744+
* Helper method that walks up the super types until the type is an instance of the Class.
745+
*/
746+
private static Type walkSuperTypesUntil(Type type, Predicate<Type> untilChecker) {
747+
while (!untilChecker.test(type)) {
748+
type = TypeUtil.getSuperType(type);
749+
}
750+
751+
return type;
752+
}
652753
}

sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/SyncRestProxy.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,9 @@ private Object handleBodyReturnType(final HttpResponseDecoder.HttpDecodedRespons
161161

162162
final Object result;
163163
if (httpMethod == HttpMethod.HEAD
164-
&& (TypeUtil.isTypeOrSubTypeOf(
165-
entityType, Boolean.TYPE) || TypeUtil.isTypeOrSubTypeOf(entityType, Boolean.class))) {
166-
boolean isSuccess = (responseStatusCode / 100) == 2;
167-
result = isSuccess;
164+
&& (TypeUtil.isTypeOrSubTypeOf(entityType, Boolean.TYPE)
165+
|| TypeUtil.isTypeOrSubTypeOf(entityType, Boolean.class))) {
166+
result = (responseStatusCode / 100) == 2;
168167
} else if (TypeUtil.isTypeOrSubTypeOf(entityType, byte[].class)) {
169168
// byte[]
170169
BinaryData binaryData = response.getSourceResponse().getBodyAsBinaryData();

0 commit comments

Comments
 (0)