From c67dffa8d439ada6fcaf86215cf54092455c8877 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:27:04 +0000 Subject: [PATCH 1/4] Initial plan From 862857ee594cd305461587b83e2d6278557a2217 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:43:58 +0000 Subject: [PATCH 2/4] Add ServiceBusJmsConnectionFactoryClassProvider interface for custom factory injection Co-authored-by: saragluna <31124698+saragluna@users.noreply.github.com> --- .../CHANGELOG.md | 2 + ...eBusJmsConnectionFactoryConfiguration.java | 9 ++- ...eBusJmsConnectionFactoryClassProvider.java | 24 ++++++ ...msConnectionFactoryConfigurationTests.java | 75 +++++++++++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index 65d97b19149e..06bf76142485 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Added `ServiceBusJmsConnectionFactoryClassProvider` interface to allow users to specify a custom subclass of `ServiceBusJmsConnectionFactory` to be used in the configuration. This enables injection of custom connection factory implementations with additional functionality beyond the standard Service Bus JMS connection factory. + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 53e4b15b4f50..6ad2f979b4fe 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -6,6 +6,7 @@ import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; +import com.azure.spring.cloud.autoconfigure.jms.ServiceBusJmsConnectionFactoryClassProvider; import jakarta.jms.ConnectionFactory; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.BeansException; @@ -118,9 +119,15 @@ private void registerJmsPoolConnectionFactory(BeanDefinitionRegistry registry) { private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() { AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class); ObjectProvider factoryCustomizers = beanFactory.getBeanProvider(AzureServiceBusJmsConnectionFactoryCustomizer.class); + ObjectProvider classProvider = beanFactory.getBeanProvider(ServiceBusJmsConnectionFactoryClassProvider.class); + + Class factoryClass = classProvider + .getIfAvailable(() -> () -> ServiceBusJmsConnectionFactory.class) + .getConnectionFactoryClass(); + return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties, factoryCustomizers.orderedStream().collect(Collectors.toList())) - .createConnectionFactory(ServiceBusJmsConnectionFactory.class); + .createConnectionFactory(factoryClass); } } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java new file mode 100644 index 000000000000..b125abb5a15c --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.jms; + +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; + +/** + * A provider for specifying the desired {@link ServiceBusJmsConnectionFactory} class to be used. + * Implement this interface and define it as a bean to inject a custom subclass of ServiceBusJmsConnectionFactory. + * + * @since 6.1.0 + */ +@FunctionalInterface +public interface ServiceBusJmsConnectionFactoryClassProvider { + + /** + * Get the class of the ServiceBusJmsConnectionFactory to be instantiated. + * The class must extend {@link ServiceBusJmsConnectionFactory} and have the required constructors. + * + * @return The class to be used for creating the ServiceBusJmsConnectionFactory instance. + */ + Class getConnectionFactoryClass(); +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java index 10c9fe284a21..1bf99e2b43e0 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java @@ -3,8 +3,12 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.core.credential.TokenCredential; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +import com.azure.spring.cloud.autoconfigure.jms.ServiceBusJmsConnectionFactoryClassProvider; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; @@ -12,6 +16,7 @@ import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.jms.connection.CachingConnectionFactory; @@ -140,9 +145,79 @@ void useCacheConnectionViaAdditionConfigurationFile(String pricingTier) { }); } + @Test + void useCustomServiceBusJmsConnectionFactoryClass() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.servicebus.pool.enabled=false", + "spring.jms.cache.enabled=false" + ) + .run(context -> { + assertThat(context).hasSingleBean(ServiceBusJmsConnectionFactory.class); + ServiceBusJmsConnectionFactory factory = context.getBean(ServiceBusJmsConnectionFactory.class); + assertThat(factory).isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + + @Test + void useCustomServiceBusJmsConnectionFactoryClassWithCaching() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.servicebus.pool.enabled=false" + ) + .run(context -> { + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory cachingFactory = context.getBean(CachingConnectionFactory.class); + assertThat(cachingFactory.getTargetConnectionFactory()).isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + + @Test + void useCustomServiceBusJmsConnectionFactoryClassWithPooling() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium" + ) + .run(context -> { + assertThat(context).hasSingleBean(JmsPoolConnectionFactory.class); + JmsPoolConnectionFactory poolFactory = context.getBean(JmsPoolConnectionFactory.class); + assertThat(poolFactory.getConnectionFactory()).isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + @Configuration @PropertySource("classpath:servicebus/additional.properties") static class AdditionalPropertySourceConfiguration { } + + @Configuration + static class CustomConnectionFactoryClassConfiguration { + @Bean + ServiceBusJmsConnectionFactoryClassProvider serviceBusJmsConnectionFactoryClassProvider() { + return () -> CustomServiceBusJmsConnectionFactory.class; + } + } + + /** + * Custom subclass of ServiceBusJmsConnectionFactory for testing. + */ + static class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory { + public CustomServiceBusJmsConnectionFactory() { + super(); + } + + public CustomServiceBusJmsConnectionFactory(String connectionString, ServiceBusJmsConnectionFactorySettings settings) { + super(connectionString, settings); + } + + public CustomServiceBusJmsConnectionFactory(TokenCredential tokenCredential, String host, ServiceBusJmsConnectionFactorySettings settings) { + super(tokenCredential, host, settings); + } + } } From 5c21d440cf641bbcdbf8d3092e03922987076c29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:52:43 +0000 Subject: [PATCH 3/4] Fix checkstyle violations by adding suppression for RedundantModifier Co-authored-by: saragluna <31124698+saragluna@users.noreply.github.com> --- .../checkstyle/track2/checkstyle-suppressions.xml | 3 +++ .../jms/ServiceBusJmsConnectionFactoryConfigurationTests.java | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/eng/lintingconfigs/checkstyle/track2/checkstyle-suppressions.xml b/eng/lintingconfigs/checkstyle/track2/checkstyle-suppressions.xml index 57efcf6e080d..b9bd10c488ce 100644 --- a/eng/lintingconfigs/checkstyle/track2/checkstyle-suppressions.xml +++ b/eng/lintingconfigs/checkstyle/track2/checkstyle-suppressions.xml @@ -43,6 +43,9 @@ + + + diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java index 1bf99e2b43e0..b79155da1554 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java @@ -206,8 +206,9 @@ ServiceBusJmsConnectionFactoryClassProvider serviceBusJmsConnectionFactoryClassP /** * Custom subclass of ServiceBusJmsConnectionFactory for testing. + * Public constructors are required for reflection-based instantiation. */ - static class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory { + public static class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory { public CustomServiceBusJmsConnectionFactory() { super(); } From 804b1be816da4aa1c8cb84ec0c83edf31d62c75b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:55:26 +0000 Subject: [PATCH 4/4] Add comprehensive JavaDoc documentation with usage examples Co-authored-by: saragluna <31124698+saragluna@users.noreply.github.com> --- ...eBusJmsConnectionFactoryClassProvider.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java index b125abb5a15c..8dc7dbc88684 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/ServiceBusJmsConnectionFactoryClassProvider.java @@ -7,7 +7,47 @@ /** * A provider for specifying the desired {@link ServiceBusJmsConnectionFactory} class to be used. + *

* Implement this interface and define it as a bean to inject a custom subclass of ServiceBusJmsConnectionFactory. + * This allows you to use a custom connection factory implementation with additional functionality beyond the + * standard Service Bus JMS connection factory. + *

+ *

+ * Example usage: + *

{@code
+ * @Configuration
+ * public class CustomJmsConfiguration {
+ *     @Bean
+ *     public ServiceBusJmsConnectionFactoryClassProvider connectionFactoryClassProvider() {
+ *         return () -> CustomServiceBusJmsConnectionFactory.class;
+ *     }
+ * }
+ *
+ * public class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory {
+ *     public CustomServiceBusJmsConnectionFactory(String connectionString, ServiceBusJmsConnectionFactorySettings settings) {
+ *         super(connectionString, settings);
+ *         // Add custom initialization
+ *     }
+ *
+ *     public CustomServiceBusJmsConnectionFactory(TokenCredential tokenCredential, String host, ServiceBusJmsConnectionFactorySettings settings) {
+ *         super(tokenCredential, host, settings);
+ *         // Add custom initialization
+ *     }
+ *
+ *     // Add custom methods or override existing ones
+ * }
+ * }
+ *

+ *

+ * Requirements: + *

    + *
  • The custom class must extend {@link ServiceBusJmsConnectionFactory}
  • + *
  • The custom class must have a constructor accepting {@code (String, ServiceBusJmsConnectionFactorySettings)} + * for connection string-based authentication
  • + *
  • The custom class must have a constructor accepting {@code (TokenCredential, String, ServiceBusJmsConnectionFactorySettings)} + * for passwordless authentication
  • + *
+ *

* * @since 6.1.0 */