This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch 3.20.x in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 3681414f1657abdb5d1cc0f7d7aa2d8345691f93 Author: James Netherton <jamesnether...@gmail.com> AuthorDate: Tue Apr 29 12:01:34 2025 +0100 Fix dynamic instantiation of Azure HttpResponseException types in native mode Fixes #7319 --- .../deployment/AzureCoreSupportProcessor.java | 23 +++++++++++++++++++--- .../deployment/AzureServicebusProcessor.java | 6 ++++++ .../azure/eventhubs/it/AzureEventhubsResource.java | 17 ++++++++++++++++ .../azure/eventhubs/it/AzureEventhubsTest.java | 8 ++++++++ .../azure/key/vault/it/AzureKeyVaultResource.java | 17 ++++++++++++++++ .../azure/key/vault/it/AzureKeyVaultTest.java | 7 +++++++ .../servicebus/it/AzureServiceBusResource.java | 17 ++++++++++++++++ .../azure/servicebus/it/AzureServiceBusTest.java | 8 ++++++++ .../storage/blob/it/AzureStorageBlobResource.java | 17 ++++++++++++++++ .../storage/blob/it/AzureStorageBlobTest.java | 8 ++++++++ .../queue/it/AzureStorageQueueResource.java | 17 ++++++++++++++++ .../storage/queue/it/AzureStorageQueueTest.java | 7 +++++++ 12 files changed, 149 insertions(+), 3 deletions(-) diff --git a/extensions-support/azure-core/deployment/src/main/java/org/apache/camel/quarkus/support/reactor/netty/deployment/AzureCoreSupportProcessor.java b/extensions-support/azure-core/deployment/src/main/java/org/apache/camel/quarkus/support/reactor/netty/deployment/AzureCoreSupportProcessor.java index 90c6cde3a1..b603a2a2c9 100644 --- a/extensions-support/azure-core/deployment/src/main/java/org/apache/camel/quarkus/support/reactor/netty/deployment/AzureCoreSupportProcessor.java +++ b/extensions-support/azure-core/deployment/src/main/java/org/apache/camel/quarkus/support/reactor/netty/deployment/AzureCoreSupportProcessor.java @@ -19,9 +19,11 @@ package org.apache.camel.quarkus.support.reactor.netty.deployment; import java.io.IOException; import java.util.Set; import java.util.function.BooleanSupplier; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.azure.core.annotation.ServiceInterface; +import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClientProvider; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; @@ -34,18 +36,22 @@ import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuil import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.util.ServiceUtil; import io.quarkus.utilities.OS; +import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; public class AzureCoreSupportProcessor { private static final DotName SERVICE_INTERFACE_DOT_NAME = DotName.createSimple(ServiceInterface.class.getName()); @BuildStep - IndexDependencyBuildItem indexDependency() { - return new IndexDependencyBuildItem("com.azure", "azure-core"); + void indexDependency(BuildProducer<IndexDependencyBuildItem> indexedDependencies) { + indexedDependencies.produce(new IndexDependencyBuildItem("com.azure", "azure-core")); + indexedDependencies.produce(new IndexDependencyBuildItem("com.azure", "azure-identity")); } @BuildStep - void reflectiveClasses(BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) { + void reflectiveClasses( + CombinedIndexBuildItem combinedIndex, + BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) { reflectiveClasses.produce(ReflectiveClassBuildItem.builder(com.azure.core.util.DateTimeRfc1123.class, com.azure.core.http.HttpHeaderName.class, com.azure.core.http.rest.StreamResponse.class, @@ -54,6 +60,17 @@ public class AzureCoreSupportProcessor { reflectiveClasses.produce(ReflectiveClassBuildItem.builder("com.microsoft.aad.msal4j.AadInstanceDiscoveryResponse", "com.microsoft.aad.msal4j.InstanceDiscoveryMetadataEntry").fields().build()); + // HttpResponseException instances may be dynamically instantiated and have methods invoked reflectively + Set<String> httpResponseExceptionClasses = combinedIndex.getIndex() + .getAllKnownSubclasses(HttpResponseException.class) + .stream() + .map(ClassInfo::name) + .map(DotName::toString) + .collect(Collectors.toUnmodifiableSet()); + + reflectiveClasses.produce(ReflectiveClassBuildItem.builder(httpResponseExceptionClasses.toArray(new String[0])) + .methods() + .build()); } @BuildStep diff --git a/extensions/azure-servicebus/deployment/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/deployment/AzureServicebusProcessor.java b/extensions/azure-servicebus/deployment/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/deployment/AzureServicebusProcessor.java index 5f532a5ef6..9b9ac0f863 100644 --- a/extensions/azure-servicebus/deployment/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/deployment/AzureServicebusProcessor.java +++ b/extensions/azure-servicebus/deployment/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/deployment/AzureServicebusProcessor.java @@ -21,6 +21,7 @@ import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.IndexDependencyBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; class AzureServicebusProcessor { @@ -43,4 +44,9 @@ class AzureServicebusProcessor { runtimeInitializedClass .produce(new RuntimeInitializedClassBuildItem(DigestProxyChallengeProcessorImpl.class.getName())); } + + @BuildStep + IndexDependencyBuildItem indexDependency() { + return new IndexDependencyBuildItem("com.azure", "azure-messaging-servicebus"); + } } diff --git a/integration-test-groups/azure/azure-eventhubs/src/main/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsResource.java b/integration-test-groups/azure/azure-eventhubs/src/main/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsResource.java index c69dd53710..44c3b9287d 100644 --- a/integration-test-groups/azure/azure-eventhubs/src/main/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsResource.java +++ b/integration-test-groups/azure/azure-eventhubs/src/main/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsResource.java @@ -23,6 +23,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.http.UnexpectedExceptionInformation; +import com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache; +import com.azure.storage.blob.implementation.models.BlobStorageExceptionInternal; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; @@ -146,4 +151,16 @@ public class AzureEventhubsResource { public void stopRoute(@PathParam("routeId") String routeId) throws Exception { context.getRouteController().stopRoute(routeId); } + + @GET + @Path("exception/cache") + @Produces(MediaType.TEXT_PLAIN) + public boolean cachedHttpResponseException() { + UnexpectedExceptionInformation exceptionInformation = new UnexpectedExceptionInformation( + BlobStorageExceptionInternal.class); + Class<? extends HttpResponseException> exceptionType = exceptionInformation.getExceptionType(); + ReflectiveInvoker reflectiveInvoker = new ResponseExceptionConstructorCache().get(exceptionType, + exceptionInformation.getExceptionBodyType()); + return reflectiveInvoker != null; + } } diff --git a/integration-test-groups/azure/azure-eventhubs/src/test/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsTest.java b/integration-test-groups/azure/azure-eventhubs/src/test/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsTest.java index 8d774afa83..80f3b95260 100644 --- a/integration-test-groups/azure/azure-eventhubs/src/test/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsTest.java +++ b/integration-test-groups/azure/azure-eventhubs/src/test/java/org/apache/camel/quarkus/component/azure/eventhubs/it/AzureEventhubsTest.java @@ -441,4 +441,12 @@ class AzureEventhubsTest { .statusCode(204); } } + + @Test + void dynamicExceptionInstantiation() { + RestAssured.get("/azure-eventhubs/exception/cache") + .then() + .statusCode(200) + .body(is("true")); + } } diff --git a/integration-test-groups/azure/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java b/integration-test-groups/azure/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java index 6e760768b1..b0f018e3f8 100644 --- a/integration-test-groups/azure/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java +++ b/integration-test-groups/azure/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java @@ -18,6 +18,11 @@ package org.apache.camel.quarkus.component.azure.key.vault.it; import java.util.concurrent.atomic.AtomicBoolean; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.http.UnexpectedExceptionInformation; +import com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache; +import com.azure.security.keyvault.secrets.implementation.models.KeyVaultErrorException; import com.azure.security.keyvault.secrets.models.KeyVaultSecret; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; @@ -138,4 +143,16 @@ public class AzureKeyVaultResource { public boolean contextReloadStatus() { return contextReloaded.get(); } + + @GET + @Path("exception/cache") + @Produces(MediaType.TEXT_PLAIN) + public boolean cachedHttpResponseException() { + UnexpectedExceptionInformation exceptionInformation = new UnexpectedExceptionInformation( + KeyVaultErrorException.class); + Class<? extends HttpResponseException> exceptionType = exceptionInformation.getExceptionType(); + ReflectiveInvoker reflectiveInvoker = new ResponseExceptionConstructorCache().get(exceptionType, + exceptionInformation.getExceptionBodyType()); + return reflectiveInvoker != null; + } } diff --git a/integration-test-groups/azure/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java b/integration-test-groups/azure/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java index 67a101fc68..04f4ad68dc 100644 --- a/integration-test-groups/azure/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java +++ b/integration-test-groups/azure/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java @@ -71,4 +71,11 @@ class AzureKeyVaultTest extends AbstractAzureKeyVaultTest { } } + @Test + void dynamicExceptionInstantiation() { + RestAssured.get("/azure-key-vault/exception/cache") + .then() + .statusCode(200) + .body(is("true")); + } } diff --git a/integration-test-groups/azure/azure-servicebus/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusResource.java b/integration-test-groups/azure/azure-servicebus/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusResource.java index e7312828b4..74a3249c2f 100644 --- a/integration-test-groups/azure/azure-servicebus/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusResource.java +++ b/integration-test-groups/azure/azure-servicebus/src/main/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusResource.java @@ -26,7 +26,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.http.UnexpectedExceptionInformation; +import com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache; import com.azure.core.util.BinaryData; +import com.azure.messaging.servicebus.administration.implementation.models.ServiceBusManagementErrorException; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; @@ -170,4 +175,16 @@ public class AzureServiceBusResource { LOG.infof("Stopping route: %s", routeId); context.getRouteController().stopRoute(routeId); } + + @GET + @Path("exception/cache") + @Produces(MediaType.TEXT_PLAIN) + public boolean cachedHttpResponseException() { + UnexpectedExceptionInformation exceptionInformation = new UnexpectedExceptionInformation( + ServiceBusManagementErrorException.class); + Class<? extends HttpResponseException> exceptionType = exceptionInformation.getExceptionType(); + ReflectiveInvoker reflectiveInvoker = new ResponseExceptionConstructorCache().get(exceptionType, + exceptionInformation.getExceptionBodyType()); + return reflectiveInvoker != null; + } } diff --git a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java index 6660ebbfc2..f922f7e782 100644 --- a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java +++ b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java @@ -355,6 +355,14 @@ class AzureServiceBusTest { } } + @Test + void dynamicExceptionInstantiation() { + RestAssured.get("/azure-servicebus/exception/cache") + .then() + .statusCode(200) + .body(is("true")); + } + static Stream<Arguments> produceConsumeOptions() { String destinationTypes = "queue"; diff --git a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobResource.java b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobResource.java index f93789156a..156af66d5d 100644 --- a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobResource.java +++ b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobResource.java @@ -30,9 +30,14 @@ import java.util.Map; import java.util.Random; import java.util.stream.Collectors; +import com.azure.core.exception.HttpResponseException; import com.azure.core.http.rest.PagedIterable; +import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.http.UnexpectedExceptionInformation; +import com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache; import com.azure.storage.blob.changefeed.models.BlobChangefeedEvent; import com.azure.storage.blob.changefeed.models.BlobChangefeedEventType; +import com.azure.storage.blob.implementation.models.BlobStorageExceptionInternal; import com.azure.storage.blob.models.BlobContainerItem; import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.models.BlobStorageException; @@ -430,6 +435,18 @@ public class AzureStorageBlobResource { } } + @GET + @Path("exception/cache") + @Produces(MediaType.TEXT_PLAIN) + public boolean cachedHttpResponseException() { + UnexpectedExceptionInformation exceptionInformation = new UnexpectedExceptionInformation( + BlobStorageExceptionInternal.class); + Class<? extends HttpResponseException> exceptionType = exceptionInformation.getExceptionType(); + ReflectiveInvoker reflectiveInvoker = new ResponseExceptionConstructorCache().get(exceptionType, + exceptionInformation.getExceptionBodyType()); + return reflectiveInvoker != null; + } + private void extractBlockNames(JsonObjectBuilder builder, List<Block> blocks, BlockListType listType) { JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); blocks.stream().map(Block::getName).forEach(arrayBuilder::add); diff --git a/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java b/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java index 3ec86637f2..ec7f2f59a9 100644 --- a/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java +++ b/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java @@ -602,4 +602,12 @@ class AzureStorageBlobTest { .statusCode(anyOf(is(204), is(404))); } } + + @Test + public void dynamicExceptionInstantiation() { + RestAssured.get("/azure-storage-blob/exception/cache") + .then() + .statusCode(200) + .body(is("true")); + } } diff --git a/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java b/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java index 9b2c4f9461..06059a05f7 100644 --- a/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java +++ b/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java @@ -23,12 +23,17 @@ import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import com.azure.core.exception.HttpResponseException; import com.azure.core.http.policy.HttpLogDetailLevel; import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.http.UnexpectedExceptionInformation; +import com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache; import com.azure.core.util.BinaryData; import com.azure.storage.common.StorageSharedKeyCredential; import com.azure.storage.queue.QueueServiceClient; import com.azure.storage.queue.QueueServiceClientBuilder; +import com.azure.storage.queue.implementation.models.QueueStorageExceptionInternal; import com.azure.storage.queue.models.PeekedMessageItem; import com.azure.storage.queue.models.QueueItem; import com.azure.storage.queue.models.QueueMessageItem; @@ -223,6 +228,18 @@ public class AzureStorageQueueResource { .collect(Collectors.joining("\n")); } + @GET + @Path("exception/cache") + @Produces(MediaType.TEXT_PLAIN) + public boolean cachedHttpResponseException() { + UnexpectedExceptionInformation exceptionInformation = new UnexpectedExceptionInformation( + QueueStorageExceptionInternal.class); + Class<? extends HttpResponseException> exceptionType = exceptionInformation.getExceptionType(); + ReflectiveInvoker reflectiveInvoker = new ResponseExceptionConstructorCache().get(exceptionType, + exceptionInformation.getExceptionBodyType()); + return reflectiveInvoker != null; + } + private String componentUri(final QueueOperationDefinition operation) { return String.format("azure-storage-queue://%s/%s?operation=%s", azureStorageAccountName, QUEUE_NAME, diff --git a/integration-test-groups/azure/azure-storage-queue/src/test/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueTest.java b/integration-test-groups/azure/azure-storage-queue/src/test/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueTest.java index 91e1c69130..a18c60357d 100644 --- a/integration-test-groups/azure/azure-storage-queue/src/test/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueTest.java +++ b/integration-test-groups/azure/azure-storage-queue/src/test/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueTest.java @@ -177,4 +177,11 @@ class AzureStorageQueueTest { .as(List.class); } + @Test + public void dynamicExceptionInstantiation() { + RestAssured.get("/azure-storage-queue/exception/cache") + .then() + .statusCode(200) + .body(is("true")); + } }