diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ResponseConstructorsCache.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ResponseConstructorsCache.java index 353caf0983b3..f236ebf96fc1 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ResponseConstructorsCache.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/ResponseConstructorsCache.java @@ -12,11 +12,8 @@ import reactor.core.Exceptions; import reactor.core.publisher.Mono; -import java.lang.invoke.LambdaMetafactory; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Comparator; import java.util.Map; @@ -29,8 +26,7 @@ */ final class ResponseConstructorsCache { private final ClientLogger logger = new ClientLogger(ResponseConstructorsCache.class); - private final Map, ResponseConstructor> cache = new ConcurrentHashMap<>(); - private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + private final Map, Constructor>> cache = new ConcurrentHashMap<>(); /** * Identify the suitable constructor for the given response class. @@ -38,7 +34,7 @@ final class ResponseConstructorsCache { * @param responseClass the response class * @return identified constructor, null if there is no match */ - ResponseConstructor get(Class> responseClass) { + Constructor> get(Class> responseClass) { return this.cache.computeIfAbsent(responseClass, this::locateResponseConstructor); } @@ -58,7 +54,8 @@ ResponseConstructor get(Class> responseClass) { * @param responseClass the response class * @return identified constructor, null if there is no match */ - private ResponseConstructor locateResponseConstructor(Class responseClass) { + @SuppressWarnings("unchecked") + private Constructor> locateResponseConstructor(Class responseClass) { Constructor[] constructors = responseClass.getDeclaredConstructors(); // Sort constructors in the "descending order" of parameter count. Arrays.sort(constructors, Comparator.comparing(Constructor::getParameterCount, (a, b) -> b - a)); @@ -66,33 +63,7 @@ private ResponseConstructor locateResponseConstructor(Class responseClass) { final int paramCount = constructor.getParameterCount(); if (paramCount >= 3 && paramCount <= 5) { try { - if (paramCount == 3) { - MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); - return new ResponseConstructor(3, LambdaMetafactory.metafactory(LOOKUP, - "apply", - ResponseFunc3.METHOD_TYPE, - ResponseFunc3.SIGNATURE, - ctrMethodHandle, - ctrMethodHandle.type()).getTarget().invoke()); - } else if (paramCount == 4) { - MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); - return new ResponseConstructor(4, LambdaMetafactory.metafactory(LOOKUP, - "apply", - ResponseFunc4.METHOD_TYPE, - ResponseFunc4.SIGNATURE, - ctrMethodHandle, - ctrMethodHandle.type()).getTarget().invoke()); - } else { - // paramCount == 5 - MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); - return new ResponseConstructor(5, LambdaMetafactory.metafactory(LOOKUP, - "apply", - ResponseFunc5.METHOD_TYPE, - ResponseFunc5.SIGNATURE, - ctrMethodHandle, - ctrMethodHandle.type()) - .getTarget().invoke()); - } + return (Constructor>) constructor; } catch (Throwable t) { throw logger.logExceptionAsError(new RuntimeException(t)); } @@ -102,131 +73,67 @@ private ResponseConstructor locateResponseConstructor(Class responseClass) { } /** - * Type that represent a {@link Response} constructor and can be used to invoke - * the same constructor. + * Invoke the constructor this type represents. + * + * @param constructor the constructor type + * @param decodedResponse the decoded http response + * @param bodyAsObject the http response content + * @return an instance of a {@link Response} implementation */ - static final class ResponseConstructor { - private final int parameterCount; - private final Object responseFunc; - - /** - * Creates ResponseConstructor. - * - * @param parameterCount the constructor parameter count - * @param responseFunc the functional interface which delegate its abstract method - * invocation to the invocation of a {@link Response} constructor - */ - private ResponseConstructor(int parameterCount, Object responseFunc) { - this.parameterCount = parameterCount; - this.responseFunc = responseFunc; - } + Mono> invoke(final Constructor> constructor, + final HttpResponseDecoder.HttpDecodedResponse decodedResponse, + final Object bodyAsObject) { + final HttpResponse httpResponse = decodedResponse.getSourceResponse(); + final HttpRequest httpRequest = httpResponse.getRequest(); + final int responseStatusCode = httpResponse.getStatusCode(); + final HttpHeaders responseHeaders = httpResponse.getHeaders(); - /** - * Invoke the {@link Response} constructor this type represents. - * - * @param decodedResponse the decoded http response - * @param bodyAsObject the http response content - * @return an instance of a {@link Response} implementation - */ - @SuppressWarnings("unchecked") - Mono> invoke(final HttpResponseDecoder.HttpDecodedResponse decodedResponse, - final Object bodyAsObject) { - final HttpResponse httpResponse = decodedResponse.getSourceResponse(); - final HttpRequest httpRequest = httpResponse.getRequest(); - final int responseStatusCode = httpResponse.getStatusCode(); - final HttpHeaders responseHeaders = httpResponse.getHeaders(); - switch (this.parameterCount) { - case 3: - try { - return Mono.just((Response) ((ResponseFunc3) this.responseFunc).apply(httpRequest, + final int paramCount = constructor.getParameterCount(); + switch (paramCount) { + case 3: + try { + return Mono.just(constructor.newInstance(httpRequest, + responseStatusCode, + responseHeaders)); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + throw logger.logExceptionAsError(Exceptions.propagate(e)); + } + case 4: + try { + return Mono.just(constructor.newInstance(httpRequest, + responseStatusCode, + responseHeaders, + bodyAsObject)); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + throw logger.logExceptionAsError(Exceptions.propagate(e)); + } + case 5: + return decodedResponse.getDecodedHeaders() + .map((Function>) decodedHeaders -> { + try { + return constructor.newInstance(httpRequest, responseStatusCode, - responseHeaders)); - } catch (Throwable t) { - throw Exceptions.propagate(t); - } - case 4: - try { - return Mono.just((Response) ((ResponseFunc4) this.responseFunc).apply(httpRequest, + responseHeaders, + bodyAsObject, + decodedHeaders); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + throw logger.logExceptionAsError(Exceptions.propagate(e)); + } + }) + .switchIfEmpty(Mono.defer((Supplier>>) () -> { + try { + return Mono.just(constructor.newInstance(httpRequest, responseStatusCode, responseHeaders, - bodyAsObject)); - } catch (Throwable t) { - throw Exceptions.propagate(t); - } - case 5: - return decodedResponse.getDecodedHeaders() - .map((Function>) decodedHeaders -> { - try { - return (Response) ((ResponseFunc5) this.responseFunc).apply(httpRequest, - responseStatusCode, - responseHeaders, - bodyAsObject, - decodedHeaders); - } catch (Throwable t) { - throw Exceptions.propagate(t); - } - }) - .switchIfEmpty(Mono.defer((Supplier>>) () -> { - try { - return Mono.just((Response) ((ResponseFunc5) this.responseFunc) - .apply(httpRequest, - responseStatusCode, - responseHeaders, - bodyAsObject, - null)); - } catch (Throwable t) { - throw Exceptions.propagate(t); - } - })); - default: - return Mono.error(new IllegalStateException( - "Response constructor with expected parameters not found.")); - } + bodyAsObject, + null)); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + throw logger.logExceptionAsError(Exceptions.propagate(e)); + } + })); + default: + throw logger.logExceptionAsError( + new IllegalStateException("Response constructor with expected parameters not found.")); } } - - @FunctionalInterface - private interface ResponseFunc3 { - MethodType SIGNATURE = MethodType.methodType(Object.class, - HttpRequest.class, - int.class, - HttpHeaders.class); - MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc3.class); - - Object apply(HttpRequest httpRequest, - int responseStatusCode, - HttpHeaders responseHeaders); - } - - @FunctionalInterface - private interface ResponseFunc4 { - MethodType SIGNATURE = MethodType.methodType(Object.class, - HttpRequest.class, - int.class, - HttpHeaders.class, - Object.class); - MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc4.class); - - Object apply(HttpRequest httpRequest, - int responseStatusCode, - HttpHeaders responseHeaders, - Object body); - } - - @FunctionalInterface - private interface ResponseFunc5 { - MethodType SIGNATURE = MethodType.methodType(Object.class, - HttpRequest.class, - int.class, - HttpHeaders.class, - Object.class, - Object.class); - MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc5.class); - - Object apply(HttpRequest httpRequest, - int responseStatusCode, - HttpHeaders responseHeaders, - Object body, - Object decodedHeaders); - } } diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java index 04206b6e75fc..3eb5f24e3ef5 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java @@ -488,9 +488,9 @@ private Mono> createResponse(HttpDecodedResponse response, Type enti "Unable to create PagedResponse. Body must be of a type that implements: " + Page.class)); } } - ResponseConstructorsCache.ResponseConstructor ctr = this.responseConstructorsCache.get(cls); + Constructor> ctr = this.responseConstructorsCache.get(cls); if (ctr != null) { - return ctr.invoke(response, bodyAsObject); + return this.responseConstructorsCache.invoke(ctr, response, bodyAsObject); } else { return Mono.error(new RuntimeException("Cannot find suitable constructor for class " + cls)); } diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheBenchMark.java b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheBenchMark.java index e99dd353c436..17cb79f24ae2 100644 --- a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheBenchMark.java +++ b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheBenchMark.java @@ -34,32 +34,32 @@ public class ResponseConstructorsCacheBenchMark { private ResponseConstructorsCacheBenchMarkTestData testData; // Cache Types private ResponseConstructorsCache defaultCache; - private ResponseConstructorsCacheReflection reflectionCache; + private ResponseConstructorsCacheLambdaMetaFactory lambdaMetaCache; private ResponseConstructorsNoCacheReflection reflectionNoCache; @Setup public void setup() { testData = new ResponseConstructorsCacheBenchMarkTestData(); defaultCache = new ResponseConstructorsCache(); - reflectionCache = new ResponseConstructorsCacheReflection(); + lambdaMetaCache = new ResponseConstructorsCacheLambdaMetaFactory(); reflectionNoCache = new ResponseConstructorsNoCacheReflection(); } @Benchmark @SuppressWarnings("unchecked") - public void lambdaMetaFactoryCache(Blackhole blackhole) { + public void reflectionCache(Blackhole blackhole) { ResponseConstructorsCacheBenchMarkTestData.Input[] inputs = testData.inputs(); for (int i = 0; i < inputs.length; i++) { Class> responseClass = (Class>) TypeUtil.getRawClass(inputs[i].returnType()); - // Step1: Locate Constructor using LambdaMetaFactory. - ResponseConstructorsCache.ResponseConstructor constructor = defaultCache.get(responseClass); + // Step1: Locate Constructor using Reflection. + Constructor> constructor = defaultCache.get(responseClass); if (constructor == null) { throw new IllegalStateException("Response constructor with expected parameters not found."); } - // Step2: Invoke Constructor using LambdaMetaFactory functional interface. - Mono> response = constructor.invoke(inputs[i].decodedResponse(), + // Step2: Invoke Constructor using Reflection. + Mono> response = defaultCache.invoke(constructor, inputs[i].decodedResponse(), inputs[i].bodyAsObject()); // avoid JVM dead code detection blackhole.consume(response.block()); @@ -68,20 +68,21 @@ public void lambdaMetaFactoryCache(Blackhole blackhole) { @Benchmark @SuppressWarnings("unchecked") - public void reflectionCache(Blackhole blackhole) { + public void lambdaMetaFactoryCache(Blackhole blackhole) { ResponseConstructorsCacheBenchMarkTestData.Input[] inputs = testData.inputs(); for (int i = 0; i < inputs.length; i++) { Class> responseClass = - (Class>) TypeUtil.getRawClass(inputs[i].returnType()); - // Step1: Locate Constructor using Reflection. - Constructor> constructor = reflectionCache.get(responseClass); + (Class>) TypeUtil.getRawClass(inputs[i].returnType()); + // Step1: Locate Constructor using LambdaMetaFactory. + ResponseConstructorsCacheLambdaMetaFactory.ResponseConstructor constructor = + lambdaMetaCache.get(responseClass); if (constructor == null) { throw new IllegalStateException("Response constructor with expected parameters not found."); } - // Step2: Invoke Constructor using Reflection. - Mono> response = reflectionCache.invoke(constructor, inputs[i].decodedResponse(), - inputs[i].bodyAsObject()); + // Step2: Invoke Constructor using LambdaMetaFactory functional interface. + Mono> response = constructor.invoke(inputs[i].decodedResponse(), + inputs[i].bodyAsObject()); // avoid JVM dead code detection blackhole.consume(response.block()); } diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheLambdaMetaFactory.java b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheLambdaMetaFactory.java new file mode 100644 index 000000000000..38b8aaa08b8c --- /dev/null +++ b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheLambdaMetaFactory.java @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.implementation; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.rest.Response; +import com.azure.core.implementation.serializer.HttpResponseDecoder; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; + +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * A concurrent cache of {@link Response} constructors. + */ +final class ResponseConstructorsCacheLambdaMetaFactory { + private final ClientLogger logger = new ClientLogger(ResponseConstructorsCache.class); + private final Map, ResponseConstructor> cache = new ConcurrentHashMap<>(); + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + /** + * Identify the suitable constructor for the given response class. + * + * @param responseClass the response class + * @return identified constructor, null if there is no match + */ + ResponseConstructor get(Class> responseClass) { + return this.cache.computeIfAbsent(responseClass, this::locateResponseConstructor); + } + + /** + * Identify the most specific constructor for the given response class. + * + * The most specific constructor is looked up following order: + * 1. (httpRequest, statusCode, headers, body, decodedHeaders) + * 2. (httpRequest, statusCode, headers, body) + * 3. (httpRequest, statusCode, headers) + * + * Developer Note: This method logic can be easily replaced with Java.Stream + * and associated operators but we're using basic sort and loop constructs + * here as this method is in hot path and Stream route is consuming a fair + * amount of resources. + * + * @param responseClass the response class + * @return identified constructor, null if there is no match + */ + private ResponseConstructor locateResponseConstructor(Class responseClass) { + Constructor[] constructors = responseClass.getDeclaredConstructors(); + // Sort constructors in the "descending order" of parameter count. + Arrays.sort(constructors, Comparator.comparing(Constructor::getParameterCount, (a, b) -> b - a)); + for (Constructor constructor : constructors) { + final int paramCount = constructor.getParameterCount(); + if (paramCount >= 3 && paramCount <= 5) { + try { + if (paramCount == 3) { + MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); + return new ResponseConstructor(3, LambdaMetafactory.metafactory(LOOKUP, + "apply", + ResponseFunc3.METHOD_TYPE, + ResponseFunc3.SIGNATURE, + ctrMethodHandle, + ctrMethodHandle.type()).getTarget().invoke()); + } else if (paramCount == 4) { + MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); + return new ResponseConstructor(4, LambdaMetafactory.metafactory(LOOKUP, + "apply", + ResponseFunc4.METHOD_TYPE, + ResponseFunc4.SIGNATURE, + ctrMethodHandle, + ctrMethodHandle.type()).getTarget().invoke()); + } else { + // paramCount == 5 + MethodHandle ctrMethodHandle = LOOKUP.unreflectConstructor(constructor); + return new ResponseConstructor(5, LambdaMetafactory.metafactory(LOOKUP, + "apply", + ResponseFunc5.METHOD_TYPE, + ResponseFunc5.SIGNATURE, + ctrMethodHandle, + ctrMethodHandle.type()) + .getTarget().invoke()); + } + } catch (Throwable t) { + throw logger.logExceptionAsError(new RuntimeException(t)); + } + } + } + return null; + } + + /** + * Type that represent a {@link Response} constructor and can be used to invoke + * the same constructor. + */ + static final class ResponseConstructor { + private final int parameterCount; + private final Object responseFunc; + + /** + * Creates ResponseConstructor. + * + * @param parameterCount the constructor parameter count + * @param responseFunc the functional interface which delegate its abstract method + * invocation to the invocation of a {@link Response} constructor + */ + private ResponseConstructor(int parameterCount, Object responseFunc) { + this.parameterCount = parameterCount; + this.responseFunc = responseFunc; + } + + /** + * Invoke the {@link Response} constructor this type represents. + * + * @param decodedResponse the decoded http response + * @param bodyAsObject the http response content + * @return an instance of a {@link Response} implementation + */ + @SuppressWarnings("unchecked") + Mono> invoke(final HttpResponseDecoder.HttpDecodedResponse decodedResponse, + final Object bodyAsObject) { + final HttpResponse httpResponse = decodedResponse.getSourceResponse(); + final HttpRequest httpRequest = httpResponse.getRequest(); + final int responseStatusCode = httpResponse.getStatusCode(); + final HttpHeaders responseHeaders = httpResponse.getHeaders(); + switch (this.parameterCount) { + case 3: + try { + return Mono.just((Response) ((ResponseFunc3) this.responseFunc).apply(httpRequest, + responseStatusCode, + responseHeaders)); + } catch (Throwable t) { + throw Exceptions.propagate(t); + } + case 4: + try { + return Mono.just((Response) ((ResponseFunc4) this.responseFunc).apply(httpRequest, + responseStatusCode, + responseHeaders, + bodyAsObject)); + } catch (Throwable t) { + throw Exceptions.propagate(t); + } + case 5: + return decodedResponse.getDecodedHeaders() + .map((Function>) decodedHeaders -> { + try { + return (Response) ((ResponseFunc5) this.responseFunc).apply(httpRequest, + responseStatusCode, + responseHeaders, + bodyAsObject, + decodedHeaders); + } catch (Throwable t) { + throw Exceptions.propagate(t); + } + }) + .switchIfEmpty(Mono.defer((Supplier>>) () -> { + try { + return Mono.just((Response) ((ResponseFunc5) this.responseFunc) + .apply(httpRequest, + responseStatusCode, + responseHeaders, + bodyAsObject, + null)); + } catch (Throwable t) { + throw Exceptions.propagate(t); + } + })); + default: + return Mono.error(new IllegalStateException( + "Response constructor with expected parameters not found.")); + } + } + } + + @FunctionalInterface + private interface ResponseFunc3 { + MethodType SIGNATURE = MethodType.methodType(Object.class, + HttpRequest.class, + int.class, + HttpHeaders.class); + MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc3.class); + + Object apply(HttpRequest httpRequest, + int responseStatusCode, + HttpHeaders responseHeaders); + } + + @FunctionalInterface + private interface ResponseFunc4 { + MethodType SIGNATURE = MethodType.methodType(Object.class, + HttpRequest.class, + int.class, + HttpHeaders.class, + Object.class); + MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc4.class); + + Object apply(HttpRequest httpRequest, + int responseStatusCode, + HttpHeaders responseHeaders, + Object body); + } + + @FunctionalInterface + private interface ResponseFunc5 { + MethodType SIGNATURE = MethodType.methodType(Object.class, + HttpRequest.class, + int.class, + HttpHeaders.class, + Object.class, + Object.class); + MethodType METHOD_TYPE = MethodType.methodType(ResponseFunc5.class); + + Object apply(HttpRequest httpRequest, + int responseStatusCode, + HttpHeaders responseHeaders, + Object body, + Object decodedHeaders); + } +} diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheReflection.java b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheReflection.java deleted file mode 100644 index f20eb81d242d..000000000000 --- a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsCacheReflection.java +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.core.implementation; - -import com.azure.core.http.HttpHeaders; -import com.azure.core.http.HttpRequest; -import com.azure.core.http.HttpResponse; -import com.azure.core.http.rest.Response; -import com.azure.core.implementation.serializer.HttpResponseDecoder; -import com.azure.core.util.logging.ClientLogger; -import reactor.core.Exceptions; -import reactor.core.publisher.Mono; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.function.Supplier; - -class ResponseConstructorsCacheReflection { - private final ClientLogger logger = new ClientLogger(ResponseConstructorsCacheReflection.class); - private final Map, Constructor>> cache = new ConcurrentHashMap<>(); - - Constructor> get(Class> responseClass) { - return this.cache.computeIfAbsent(responseClass, this::locateResponseConstructor); - } - - @SuppressWarnings("unchecked") - private Constructor> locateResponseConstructor(Class responseClass) { - Constructor[] constructors = responseClass.getDeclaredConstructors(); - // Sort constructors in the "descending order" of parameter count. - Arrays.sort(constructors, Comparator.comparing(Constructor::getParameterCount, (a, b) -> b - a)); - for (Constructor constructor : constructors) { - final int paramCount = constructor.getParameterCount(); - if (paramCount >= 3 && paramCount <= 5) { - try { - return (Constructor>) constructor; - } catch (Throwable t) { - throw logger.logExceptionAsError(new RuntimeException(t)); - } - } - } - return null; - } - - Mono> invoke(final Constructor> constructor, - final HttpResponseDecoder.HttpDecodedResponse decodedResponse, - final Object bodyAsObject) { - final HttpResponse httpResponse = decodedResponse.getSourceResponse(); - final HttpRequest httpRequest = httpResponse.getRequest(); - final int responseStatusCode = httpResponse.getStatusCode(); - final HttpHeaders responseHeaders = httpResponse.getHeaders(); - - final int paramCount = constructor.getParameterCount(); - switch (paramCount) { - case 3: - try { - return Mono.just(constructor.newInstance(httpRequest, - responseStatusCode, - responseHeaders)); - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw Exceptions.propagate(e); - } - case 4: - try { - return Mono.just(constructor.newInstance(httpRequest, - responseStatusCode, - responseHeaders, - bodyAsObject)); - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw Exceptions.propagate(e); - } - case 5: - return decodedResponse.getDecodedHeaders() - .map((Function>) decodedHeaders -> { - try { - return constructor.newInstance(httpRequest, - responseStatusCode, - responseHeaders, - bodyAsObject, - decodedHeaders); - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw Exceptions.propagate(e); - } - }) - .switchIfEmpty(Mono.defer((Supplier>>) () -> { - try { - return Mono.just(constructor.newInstance(httpRequest, - responseStatusCode, - responseHeaders, - bodyAsObject, - null)); - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw Exceptions.propagate(e); - } - })); - default: - throw new IllegalStateException("Response constructor with expected parameters not found."); - } - } -} diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsNoCacheReflection.java b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsNoCacheReflection.java index efc067d840bb..b220dce894a6 100644 --- a/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsNoCacheReflection.java +++ b/sdk/core/azure-core/src/test/java/com/azure/core/implementation/ResponseConstructorsNoCacheReflection.java @@ -20,7 +20,7 @@ import java.util.function.Supplier; class ResponseConstructorsNoCacheReflection { - private final ClientLogger logger = new ClientLogger(ResponseConstructorsCacheReflection.class); + private final ClientLogger logger = new ClientLogger(ResponseConstructorsCacheLambdaMetaFactory.class); Constructor> get(Class> responseClass) { return locateResponseConstructor(responseClass); @@ -96,7 +96,8 @@ Mono> invoke(final Constructor> constructor, } })); default: - throw new IllegalStateException("Response constructor with expected parameters not found."); + throw logger.logExceptionAsError( + new IllegalStateException("Response constructor with expected parameters not found.")); } } }