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"));
+    }
 }

Reply via email to