From aea81ba8973ba0d20f28c8f0fd0dd351e42691d3 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 09:51:25 +0800 Subject: [PATCH 01/23] Fix code smells --- .../AzureMessagingListenerAutoConfiguration.java | 8 ++++---- .../ServiceBusProcessorClientLifecycleManager.java | 2 +- .../implementation/core/annotation/EventHubsListener.java | 2 +- .../EventHubsListenerAnnotationBeanPostProcessor.java | 2 +- .../core/annotation/ServiceBusListener.java | 2 +- .../ServiceBusListenerAnnotationBeanPostProcessor.java | 4 ++-- .../implementation/config/AzureListenerEndpoint.java | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java index ee1c360a9459..1225e1c076ea 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java @@ -49,8 +49,8 @@ public class AzureMessagingListenerAutoConfiguration { @Configuration @ConditionalOnBean(EventHubsProcessorFactory.class) static class EventHubsConfiguration { - @Bean(name = "azureEventHubsListenerContainerFactory") - @ConditionalOnMissingBean(name = "azureEventHubsListenerContainerFactory") + @Bean(name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @ConditionalOnMissingBean(name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) public MessageListenerContainerFactory azureEventHubsListenerContainerFactory( EventHubsProcessorFactory eventHubsProcessorFactory, ObjectProvider> messageConverterProvider) { @@ -73,8 +73,8 @@ static class EnableEventHubsConfiguration { @Configuration @ConditionalOnBean(ServiceBusProcessorFactory.class) static class ServiceBusConfiguration { - @Bean(name = "azureServiceBusListenerContainerFactory") - @ConditionalOnMissingBean(name = "azureServiceBusListenerContainerFactory") + @Bean(name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @ConditionalOnMissingBean(name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) public MessageListenerContainerFactory azureServiceBusListenerContainerFactory( ServiceBusProcessorFactory serviceBusProcessorFactory, ObjectProvider> messageConverterProvider) { diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java index bc34275b242b..11d83b7f8be6 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java @@ -14,7 +14,7 @@ * Helper class to control the lifecycle of a {@link ServiceBusProcessorClient}. * This class implements {@code SmartLifecycle} to auto start {@link ServiceBusProcessorClient} when the Spring Application Context starts, * And stop the {@link ServiceBusProcessorClient} when the Spring Application Context stops. - * NOTE, there is not need to call {@link #start()} or {@link #stop()} explicitly, as the {@link ServiceBusProcessorClient} will be started and stopped automatically. + * NOTE, there is no need to call {@link #start()} or {@link #stop()} explicitly, as the {@link ServiceBusProcessorClient} will be started and stopped automatically. * And since the {@link ServiceBusProcessorClient} is a {@link AutoCloseable}, there is no need to call {@link ServiceBusProcessorClient#close()} explicitly. */ public class ServiceBusProcessorClientLifecycleManager implements SmartLifecycle { diff --git a/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListener.java b/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListener.java index 968b79e3c680..a3e6a6fc0bb1 100644 --- a/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListener.java +++ b/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListener.java @@ -20,7 +20,7 @@ * specified {@link #destination}. The {@link #containerFactory} identifies the * {@link MessageListenerContainerFactory} to use to build * the Azure listener container. If not set, a default container factory is - * assumed to be available with a bean name of {@code eventHubsListenerContainerFactory} + * assumed to be available with a bean name of {@code azureEventHubsListenerContainerFactory} * unless an explicit default has been provided through configuration. * *

Processing of {@code @EventHubsListener} annotations is performed by registering a diff --git a/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListenerAnnotationBeanPostProcessor.java b/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListenerAnnotationBeanPostProcessor.java index da40c1b3065f..715740a5f7fb 100644 --- a/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListenerAnnotationBeanPostProcessor.java +++ b/sdk/spring/spring-messaging-azure-eventhubs/src/main/java/com/azure/spring/messaging/eventhubs/implementation/core/annotation/EventHubsListenerAnnotationBeanPostProcessor.java @@ -42,7 +42,7 @@ public class EventHubsListenerAnnotationBeanPostProcessor extends AzureListenerAnnotationBeanPostProcessorAdapter { public static final String DEFAULT_EVENT_HUBS_LISTENER_ANNOTATION_BPP_BEAN_NAME = "eventHubsListenerAnnotationBeanPostProcessor"; - private static final String DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "azureEventHubsListenerContainerFactory"; + public static final String DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "azureEventHubsListenerContainerFactory"; /** * Construct an {@link EventHubsListenerAnnotationBeanPostProcessor} instance with default configuration. diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListener.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListener.java index 2de391e86e36..f1009cba2384 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListener.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListener.java @@ -20,7 +20,7 @@ * specified {@link #destination}. The {@link #containerFactory} identifies the * {@link MessageListenerContainerFactory} to use to build * the Azure listener container. If not set, a default container factory is - * assumed to be available with a bean name of {@code serviceBusListenerContainerFactory} + * assumed to be available with a bean name of {@code azureServiceBusListenerContainerFactory} * unless an explicit default has been provided through configuration. * *

Processing of {@code @ServiceBusListener} annotations is performed by registering a diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListenerAnnotationBeanPostProcessor.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListenerAnnotationBeanPostProcessor.java index 10496af577f1..e9c7add84901 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListenerAnnotationBeanPostProcessor.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/core/annotation/ServiceBusListenerAnnotationBeanPostProcessor.java @@ -43,7 +43,7 @@ public class ServiceBusListenerAnnotationBeanPostProcessor extends AzureListenerAnnotationBeanPostProcessorAdapter { public static final String DEFAULT_SERVICE_BUS_LISTENER_ANNOTATION_BPP_BEAN_NAME = "serviceBusListenerAnnotationBeanPostProcessor"; - private static final String DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "azureServiceBusListenerContainerFactory"; + public static final String DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "azureServiceBusListenerContainerFactory"; /** * Construct an {@link ServiceBusListenerAnnotationBeanPostProcessor} instance with default configuration. @@ -64,7 +64,7 @@ protected AzureListenerEndpoint createAndConfigureMethodListenerEndpoint(Service BeanFactory beanFactory, MessageHandlerMethodFactory messageHandlerMethodFactory) { MethodServiceBusListenerEndpoint endpoint = new MethodServiceBusListenerEndpoint(); - + endpoint.setBean(bean); endpoint.setMethod(method); endpoint.setBeanFactory(beanFactory); diff --git a/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java b/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java index 5ba0d9fafc5f..ff0226b3c7a8 100644 --- a/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java +++ b/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java @@ -8,7 +8,7 @@ import com.azure.spring.messaging.listener.MessageListenerContainer; /** - * Model for a Azure listener endpoint. Can be used against a {@link AzureListenerConfigurer AzureListenerConfigurer} to + * Model for an Azure listener endpoint. Can be used against a {@link AzureListenerConfigurer AzureListenerConfigurer} to * register endpoints programmatically. */ public interface AzureListenerEndpoint { From 9410f504ad33b36f6269cbfbb2c85b27dcc57de4 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 14:00:54 +0800 Subject: [PATCH 02/23] Support to inherit ServiceBusClientBuilder configurations --- .../AzureServiceBusCommonProperties.java | 16 ++++++++ .../properties/AzureServiceBusProperties.java | 6 +++ .../AzureServiceBusPropertiesTest.java | 24 ++++++++++++ ...ractServiceBusSubClientBuilderFactory.java | 34 ++++++++++------ .../ServiceBusClientCommonProperties.java | 9 +++++ ...erviceBusSubClientBuilderFactoryTests.java | 39 +++++++++++++++++++ .../ServiceBusClientCommonTestProperties.java | 10 +++++ .../core/properties/CommonProperties.java | 16 ++++++++ .../ConsumerPropertiesParentMerger.java | 2 + .../merger/ProcessorPropertiesMerger.java | 1 + .../ProcessorPropertiesParentMerger.java | 1 + .../merger/SenderPropertiesParentMerger.java | 2 + .../ConsumerPropertiesParentMergerTests.java | 15 +++++++ .../ProcessorPropertiesParentMergerTests.java | 15 +++++++ 14 files changed, 179 insertions(+), 11 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java index 642cca5fdad0..fbe0d307ea46 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java @@ -42,6 +42,14 @@ public abstract class AzureServiceBusCommonProperties extends AbstractAzureAmqpC */ private String customEndpointAddress; + /** + * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the sender, receiver or + * processor properties. Defaults to true (existing behavior). Set to false to preserve configuration already set on + * the shared builder, for example the ClientOptions carrying TracingOptions set through an + * AzureServiceClientBuilderCustomizer. + */ + private Boolean inheritConfiguration; + private String extractFqdnFromConnectionString() { if (this.connectionString == null) { return null; @@ -107,4 +115,12 @@ public String getCustomEndpointAddress() { public void setCustomEndpointAddress(String customEndpointAddress) { this.customEndpointAddress = customEndpointAddress; } + + public Boolean getInheritConfiguration() { + return inheritConfiguration; + } + + public void setInheritConfiguration(Boolean inheritConfiguration) { + this.inheritConfiguration = inheritConfiguration; + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java index a4f287cd8366..13059d8b286e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java @@ -69,6 +69,7 @@ public Producer buildProducerProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); + propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.producer.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.producer.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -76,6 +77,7 @@ public Producer buildProducerProperties() { propertyMapper.from(this.producer.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.producer.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.producer.getEntityName()).to(properties::setEntityName); + propertyMapper.from(this.producer.getInheritConfiguration()).to(properties::setInheritConfiguration); return properties; } @@ -93,6 +95,7 @@ public Consumer buildConsumerProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); + propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.consumer.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.consumer.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -100,6 +103,7 @@ public Consumer buildConsumerProperties() { propertyMapper.from(this.consumer.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.consumer.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.consumer.getEntityName()).to(properties::setEntityName); + propertyMapper.from(this.consumer.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.consumer.getSessionEnabled()).to(properties::setSessionEnabled); propertyMapper.from(this.consumer.getAutoComplete()).to(properties::setAutoComplete); @@ -125,6 +129,7 @@ public Processor buildProcessorProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); + propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.processor.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.processor.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -132,6 +137,7 @@ public Processor buildProcessorProperties() { propertyMapper.from(this.processor.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.processor.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.processor.getEntityName()).to(properties::setEntityName); + propertyMapper.from(this.processor.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.processor.getSessionEnabled()).to(properties::setSessionEnabled); propertyMapper.from(this.processor.getAutoComplete()).to(properties::setAutoComplete); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java index aad5020e037a..1fb5f916fe0d 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java @@ -107,6 +107,30 @@ void childrenWillInheritParent() { assertEquals(customEndpoint, processor.getCustomEndpointAddress()); } + @Test + void inheritConfigurationDefaultsToNull() { + AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); + assertNull(serviceBusProperties.getInheritConfiguration()); + assertNull(serviceBusProperties.buildProducerProperties().getInheritConfiguration()); + assertNull(serviceBusProperties.buildConsumerProperties().getInheritConfiguration()); + assertNull(serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); + } + + @Test + void inheritConfigurationIsInheritedByChildrenAndOverridableByChild() { + AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); + serviceBusProperties.setInheritConfiguration(true); + + // Children inherit the namespace-level inherit-configuration value. + assertEquals(Boolean.TRUE, serviceBusProperties.buildProducerProperties().getInheritConfiguration()); + assertEquals(Boolean.TRUE, serviceBusProperties.buildConsumerProperties().getInheritConfiguration()); + assertEquals(Boolean.TRUE, serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); + + // A child-level value takes precedence over the namespace-level value. + serviceBusProperties.getProcessor().setInheritConfiguration(false); + assertEquals(Boolean.FALSE, serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); + } + @Test void buildProducerPropertiesUseParent() { AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 060dfc07a26f..e286c0a74753 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -109,10 +109,22 @@ protected boolean isShareServiceBusClientBuilder() { return shareServiceBusClientBuilder; } + private boolean isInheritConfiguration() { + // Not set defaults to true, preserving the existing behavior. + return this.properties.getInheritConfiguration() == null || this.properties.getInheritConfiguration(); + } + + // In the non-shared path the sub-client builder applies its property-derived configuration to the underlying + // ServiceBusClientBuilder when inherit-configuration is true (the default). Set it to false to preserve configuration + // already set on the shared builder (e.g. ClientOptions carrying TracingOptions from a customizer). See #49742. + private boolean shouldConfigureServiceBusClientBuilder() { + return !isShareServiceBusClientBuilder() && isInheritConfiguration(); + } + @Override protected BiConsumer consumeProxyOptions() { return (builder, proxy) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().proxyOptions(proxy); } }; @@ -121,7 +133,7 @@ protected BiConsumer consumeProxyOptions() { @Override protected BiConsumer consumeAmqpTransportType() { return (builder, t) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().transportType(t); } }; @@ -130,7 +142,7 @@ protected BiConsumer consumeAmqpTransportType() { @Override protected BiConsumer consumeAmqpRetryOptions() { return (builder, retry) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().retryOptions(retry); } }; @@ -139,7 +151,7 @@ protected BiConsumer consumeAmqpRetryOptions() { @Override protected BiConsumer consumeClientOptions() { return (builder, client) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().clientOptions(client); } }; @@ -154,17 +166,17 @@ protected AzureProperties getAzureProperties() { protected List> getAuthenticationDescriptors(T builder) { return Arrays.asList( new NamedKeyAuthenticationDescriptor(credential -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }), new SasAuthenticationDescriptor(credential -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }), new TokenAuthenticationDescriptor(this.tokenCredentialResolver, credential -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }) @@ -174,7 +186,7 @@ protected List> getAuthenticationDescriptors(T build @Override protected BiConsumer consumeConfiguration() { return (builder, configuration) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().configuration(configuration); } }; @@ -183,7 +195,7 @@ protected BiConsumer consumeConfiguration() { @Override protected BiConsumer consumeDefaultTokenCredential() { return (builder, credential) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }; @@ -192,7 +204,7 @@ protected BiConsumer consumeDefaultTokenCredential() { @Override protected BiConsumer consumeConnectionString() { return (builder, connectionString) -> { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().connectionString(connectionString); } }; @@ -200,7 +212,7 @@ protected BiConsumer consumeConnectionString() { @Override protected void configureService(T builder) { - if (!isShareServiceBusClientBuilder()) { + if (shouldConfigureServiceBusClientBuilder()) { getServiceBusClientBuilder().fullyQualifiedNamespace(properties.getFullyQualifiedNamespace()); } } diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java index 1de72d2ec087..675f9e8406a8 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java @@ -32,4 +32,13 @@ public interface ServiceBusClientCommonProperties extends AzureProperties, Retry * @return the custom endpoint address. */ String getCustomEndpointAddress(); + + /** + * Whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this sub-client's + * properties. When {@code null} (the default) it is treated as {@code true}, preserving the existing behavior. Set to + * {@code false} to keep configuration already present on the shared builder, for example {@code ClientOptions} + * carrying {@code TracingOptions} set through an {@code AzureServiceClientBuilderCustomizer}. + * @return whether the shared {@code ServiceBusClientBuilder} inherits this sub-client's property configuration. + */ + Boolean getInheritConfiguration(); } diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java index 5be7bf0f0e83..f06d5d051bee 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -135,6 +136,44 @@ void connectionStringConfigured(boolean isShareServiceClientBuilder) { verify(factory.getServiceBusClientBuilder(), times(1)).connectionString(connectionString); } + @Test + void inheritConfigurationFalseSkipsConfiguringServiceBusClientBuilder() { + P properties = createMinimalServiceProperties(); + properties.setShareServiceBusClientBuilder(false); + properties.setInheritConfiguration(false); + final F factory = createClientBuilderFactoryWithMockBuilder(properties); + doReturn(false).when(factory).isShareServiceBusClientBuilder(); + ServiceBusClientBuilder rootBuilder = mock(ServiceBusClientBuilder.class); + doReturn(rootBuilder).when(factory).getServiceBusClientBuilder(); + + B builder = factory.build(); + buildClient(builder); + + // With inherit-configuration=false, the sub-client builder factory must not overwrite the shared builder, so + // that a customizer-configured builder (e.g. ClientOptions carrying TracingOptions) is preserved. See #49742. + verify(rootBuilder, times(0)).fullyQualifiedNamespace(any()); + verify(rootBuilder, times(0)).clientOptions(any()); + verify(rootBuilder, times(0)).proxyOptions(any()); + verify(rootBuilder, times(0)).retryOptions(any()); + verify(rootBuilder, times(0)).transportType(any()); + } + + @Test + void inheritConfigurationNotSetConfiguresServiceBusClientBuilder() { + P properties = createMinimalServiceProperties(); + properties.setShareServiceBusClientBuilder(false); + final F factory = createClientBuilderFactoryWithMockBuilder(properties); + doReturn(false).when(factory).isShareServiceBusClientBuilder(); + ServiceBusClientBuilder rootBuilder = mock(ServiceBusClientBuilder.class); + doReturn(rootBuilder).when(factory).getServiceBusClientBuilder(); + + B builder = factory.build(); + buildClient(builder); + + // By default (unset, treated as true) the behavior is unchanged: the shared builder is configured. + verify(rootBuilder, atLeast(1)).fullyQualifiedNamespace(properties.getFullyQualifiedNamespace()); + } + private void verifyFqdnConfigured(boolean isShareServiceClientBuilder) { P properties = createMinimalServiceProperties(); properties.setShareServiceBusClientBuilder(isShareServiceClientBuilder); diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java index 2a7f915e4f8e..75d5f33f0223 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java @@ -19,6 +19,7 @@ public class ServiceBusClientCommonTestProperties extends AzureAmqpSdkProperties private String customEndpointAddress; private boolean shareServiceBusClientBuilder; + private Boolean inheritConfiguration; private String extractFqdnFromConnectionString() { if (this.connectionString == null) { @@ -93,4 +94,13 @@ public boolean isShareServiceBusClientBuilder() { public void setShareServiceBusClientBuilder(boolean shareServiceBusClientBuilder) { this.shareServiceBusClientBuilder = shareServiceBusClientBuilder; } + + @Override + public Boolean getInheritConfiguration() { + return inheritConfiguration; + } + + public void setInheritConfiguration(Boolean inheritConfiguration) { + this.inheritConfiguration = inheritConfiguration; + } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java index 67b0295d82d1..f8851c3cde7e 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java @@ -29,6 +29,7 @@ public CommonProperties() { private String entityName; private ServiceBusEntityType entityType; private String customEndpointAddress; + private Boolean inheritConfiguration; private String extractFqdnFromConnectionString() { if (this.connectionString == null) { @@ -126,4 +127,19 @@ public String getCustomEndpointAddress() { public void setCustomEndpointAddress(String customEndpointAddress) { this.customEndpointAddress = customEndpointAddress; } + + @Override + public Boolean getInheritConfiguration() { + return inheritConfiguration; + } + + /** + * Set whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this + * sub-client's properties. Defaults to {@code true}; set to {@code false} to preserve configuration already set on + * the shared builder. + * @param inheritConfiguration whether to inherit the shared {@code ServiceBusClientBuilder} configuration. + */ + public void setInheritConfiguration(Boolean inheritConfiguration) { + this.inheritConfiguration = inheritConfiguration; + } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java index 30581e597fb9..f4e5c6a0e6d6 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java @@ -40,6 +40,7 @@ public ConsumerProperties merge(ConsumerProperties child, NamespaceProperties pa propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); + propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); // If a same property appears in both two objects, the value from the child will take precedence. copyConsumerPropertiesIfNotNull(child, properties); @@ -56,6 +57,7 @@ public static void copyConsumerPropertiesIfNotNull(ConsumerProperties source, Co propertyMapper.from(source.getEntityName()).to(target::setEntityName); propertyMapper.from(source.getEntityType()).to(target::setEntityType); propertyMapper.from(source.getCustomEndpointAddress()).to(target::setCustomEndpointAddress); + propertyMapper.from(source.getInheritConfiguration()).to(target::setInheritConfiguration); propertyMapper.from(source.getSessionEnabled()).to(target::setSessionEnabled); propertyMapper.from(source.getAutoComplete()).to(target::setAutoComplete); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java index 12037e8e581b..c4433637c215 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java @@ -47,6 +47,7 @@ public static void copyProcessorPropertiesIfNotNull(ProcessorProperties source, propertyMapper.from(source.getMaxConcurrentSessions()).to(target::setMaxConcurrentSessions); propertyMapper.from(source.getMaxConcurrentCalls()).to(target::setMaxConcurrentCalls); propertyMapper.from(source.getCustomEndpointAddress()).to(target::setCustomEndpointAddress); + propertyMapper.from(source.getInheritConfiguration()).to(target::setInheritConfiguration); propertyMapper.from(source.getSessionEnabled()).to(target::setSessionEnabled); propertyMapper.from(source.getSessionIdleTimeout()).to(target::setSessionIdleTimeout); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java index 5ed82165733c..73aa0654f185 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java @@ -38,6 +38,7 @@ public ProcessorProperties merge(ProcessorProperties child, NamespaceProperties propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); + propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); // If a same property appears in both two objects, the value from the child will take precedence. ProcessorPropertiesMerger.copyProcessorPropertiesIfNotNull(child, properties); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java index d0b8b651d1a9..a50796f9b01b 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java @@ -39,6 +39,7 @@ public ProducerProperties merge(ProducerProperties child, NamespaceProperties pa propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); + propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(child.getDomainName()).to(properties::setDomainName); propertyMapper.from(child.getNamespace()).to(properties::setNamespace); @@ -46,6 +47,7 @@ public ProducerProperties merge(ProducerProperties child, NamespaceProperties pa propertyMapper.from(child.getEntityName()).to(properties::setEntityName); propertyMapper.from(child.getEntityType()).to(properties::setEntityType); propertyMapper.from(child.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); + propertyMapper.from(child.getInheritConfiguration()).to(properties::setInheritConfiguration); return properties; diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java index b94b240f2d4a..5307cb7fd626 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java @@ -12,6 +12,7 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ConsumerPropertiesParentMergerTests { @@ -74,4 +75,18 @@ void childProvidedShouldUseChild() { result.getProfile().getEnvironment().getActiveDirectoryEndpoint()); assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } + + @Test + void inheritConfigurationShouldFollowParentChildPrecedence() { + NamespaceProperties parent = new NamespaceProperties(); + parent.setInheritConfiguration(true); + + // Parent value is used when the child does not set it. + assertTrue(merger.merge(new ConsumerProperties(), parent).getInheritConfiguration()); + + // Child value takes precedence over the parent value. + ConsumerProperties child = new ConsumerProperties(); + child.setInheritConfiguration(false); + assertFalse(merger.merge(child, parent).getInheritConfiguration()); + } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java index 9fe419176840..f19534038fb3 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java @@ -14,6 +14,7 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ProcessorPropertiesParentMergerTests { @@ -82,4 +83,18 @@ void childProvidedShouldUseChild() { assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } + @Test + void inheritConfigurationShouldFollowParentChildPrecedence() { + NamespaceProperties parent = new NamespaceProperties(); + parent.setInheritConfiguration(true); + + // Parent value is used when the child does not set it. + assertTrue(merger.merge(new ProcessorProperties(), parent).getInheritConfiguration()); + + // Child value takes precedence over the parent value. + ProcessorProperties child = new ProcessorProperties(); + child.setInheritConfiguration(false); + assertFalse(merger.merge(child, parent).getInheritConfiguration()); + } + } From 89aa78694f2f615c5f0ea58937c79a1f67309807 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 14:06:42 +0800 Subject: [PATCH 03/23] Update CHANGELOG --- sdk/spring/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index e15247907a52..75a46f2073fd 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -10,6 +10,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses ([#49676](https://github.com/Azure/azure-sdk-for-java/pull/49676)). - Added support for constructing `AadB2cAuthorizationRequestResolver` with a custom `authorizationRequestBaseUri`, aligning Azure AD B2C authorization request resolution with the configurability already available for AAD. ([#49674](https://github.com/Azure/azure-sdk-for-java/pull/49674)) +- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `true`, preserving the existing behavior. Set it to `false` to prevent the sender, receiver or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). #### Breaking Changes From 0e8b41e7fa566973334353d2ef4e397df79a53f1 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 14:24:33 +0800 Subject: [PATCH 04/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../servicebus/core/properties/CommonProperties.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java index f8851c3cde7e..e9b381fd88f8 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java @@ -135,8 +135,8 @@ public Boolean getInheritConfiguration() { /** * Set whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this - * sub-client's properties. Defaults to {@code true}; set to {@code false} to preserve configuration already set on - * the shared builder. + * sub-client's properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior; set + * to {@code false} to preserve configuration already set on the shared builder. * @param inheritConfiguration whether to inherit the shared {@code ServiceBusClientBuilder} configuration. */ public void setInheritConfiguration(Boolean inheritConfiguration) { From d241457b1aa52bea73a7e0589645e2ca3a5b8ed2 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 14:24:51 +0800 Subject: [PATCH 05/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../properties/AzureServiceBusCommonProperties.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java index fbe0d307ea46..e9dbc28a0937 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java @@ -44,9 +44,9 @@ public abstract class AzureServiceBusCommonProperties extends AbstractAzureAmqpC /** * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the sender, receiver or - * processor properties. Defaults to true (existing behavior). Set to false to preserve configuration already set on - * the shared builder, for example the ClientOptions carrying TracingOptions set through an - * AzureServiceClientBuilderCustomizer. + * processor properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. Set to + * {@code false} to preserve configuration already set on the shared builder, for example the ClientOptions carrying + * TracingOptions set through an AzureServiceClientBuilderCustomizer. */ private Boolean inheritConfiguration; From a5e20d2aa60c8db2a0532502d21c4c009fdb3407 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 14:41:41 +0800 Subject: [PATCH 06/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 75a46f2073fd..68951c777e82 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -10,7 +10,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses ([#49676](https://github.com/Azure/azure-sdk-for-java/pull/49676)). - Added support for constructing `AadB2cAuthorizationRequestResolver` with a custom `authorizationRequestBaseUri`, aligning Azure AD B2C authorization request resolution with the configurability already available for AAD. ([#49674](https://github.com/Azure/azure-sdk-for-java/pull/49674)) -- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `true`, preserving the existing behavior. Set it to `false` to prevent the sender, receiver or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). +- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `null` (treated as `true`), preserving the existing behavior. Set it to `false` to prevent the sender, receiver or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). #### Breaking Changes From 0c0c04c835064d72cf79ccec6e2c6dba4a770832 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Jul 2026 06:50:03 +0000 Subject: [PATCH 07/23] Add producer inheritConfiguration precedence test Co-authored-by: moarychan <19926623+moarychan@users.noreply.github.com> --- .../ProducerPropertiesParentMergerTests.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java index a3481a376cac..3051cb27ad81 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java @@ -12,6 +12,8 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ProducerPropertiesParentMergerTests { private final SenderPropertiesParentMerger merger = new SenderPropertiesParentMerger(); @@ -67,4 +69,18 @@ void childProvidedShouldUseChild() { assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } + @Test + void inheritConfigurationShouldFollowParentChildPrecedence() { + NamespaceProperties parent = new NamespaceProperties(); + parent.setInheritConfiguration(true); + + // Parent value is used when the child does not set it. + assertTrue(merger.merge(new ProducerProperties(), parent).getInheritConfiguration()); + + // Child value takes precedence over the parent value. + ProducerProperties child = new ProducerProperties(); + child.setInheritConfiguration(false); + assertFalse(merger.merge(child, parent).getInheritConfiguration()); + } + } From 30cb85509d04c0dce1823bb282f5ec9ee8c1f1ae Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 15:44:48 +0800 Subject: [PATCH 08/23] Correct the terminology --- sdk/spring/CHANGELOG.md | 2 +- .../servicebus/properties/AzureServiceBusCommonProperties.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 68951c777e82..79f7db45291e 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -10,7 +10,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses ([#49676](https://github.com/Azure/azure-sdk-for-java/pull/49676)). - Added support for constructing `AadB2cAuthorizationRequestResolver` with a custom `authorizationRequestBaseUri`, aligning Azure AD B2C authorization request resolution with the configurability already available for AAD. ([#49674](https://github.com/Azure/azure-sdk-for-java/pull/49674)) -- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `null` (treated as `true`), preserving the existing behavior. Set it to `false` to prevent the sender, receiver or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). +- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `null` (treated as `true`), preserving the existing behavior. Set it to `false` to prevent the producer, consumer or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). #### Breaking Changes diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java index e9dbc28a0937..ee10fd20c972 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java @@ -43,7 +43,7 @@ public abstract class AzureServiceBusCommonProperties extends AbstractAzureAmqpC private String customEndpointAddress; /** - * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the sender, receiver or + * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the producer, consumer or * processor properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. Set to * {@code false} to preserve configuration already set on the shared builder, for example the ClientOptions carrying * TracingOptions set through an AzureServiceClientBuilderCustomizer. From 3c89758bd950b43668883af00228b996f1115752 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 16:42:03 +0800 Subject: [PATCH 09/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../factory/AbstractServiceBusSubClientBuilderFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index e286c0a74753..6dc6ccc0040f 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -114,9 +114,10 @@ private boolean isInheritConfiguration() { return this.properties.getInheritConfiguration() == null || this.properties.getInheritConfiguration(); } - // In the non-shared path the sub-client builder applies its property-derived configuration to the underlying - // ServiceBusClientBuilder when inherit-configuration is true (the default). Set it to false to preserve configuration - // already set on the shared builder (e.g. ClientOptions carrying TracingOptions from a customizer). See #49742. + // In the non-shared path, the sub-client builder applies its property-derived configuration to the underlying + // ServiceBusClientBuilder when inherit-configuration is true (the default). + // Set it to false to preserve configuration already set on the shared builder (for example, ClientOptions carrying + // TracingOptions from a customizer). See #49742. private boolean shouldConfigureServiceBusClientBuilder() { return !isShareServiceBusClientBuilder() && isInheritConfiguration(); } From 4edd56ea28b309f5c7beff36fb3291d0de134b3b Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 16:42:19 +0800 Subject: [PATCH 10/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../properties/ServiceBusClientCommonProperties.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java index 675f9e8406a8..8270d4b521cf 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java @@ -34,10 +34,10 @@ public interface ServiceBusClientCommonProperties extends AzureProperties, Retry String getCustomEndpointAddress(); /** - * Whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this sub-client's - * properties. When {@code null} (the default) it is treated as {@code true}, preserving the existing behavior. Set to - * {@code false} to keep configuration already present on the shared builder, for example {@code ClientOptions} - * carrying {@code TracingOptions} set through an {@code AzureServiceClientBuilderCustomizer}. + * Whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this + * sub-client's properties. When {@code null} (the default) it is treated as {@code true}, preserving the existing + * behavior. Set to {@code false} to keep configuration already present on the shared builder, for example + * {@code ClientOptions} carrying {@code TracingOptions} set through an {@code AzureServiceClientBuilderCustomizer}. * @return whether the shared {@code ServiceBusClientBuilder} inherits this sub-client's property configuration. */ Boolean getInheritConfiguration(); From 2227e3253316f7a78daf9a1c094ec3fec1df5455 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 16:42:35 +0800 Subject: [PATCH 11/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../properties/AzureServiceBusCommonProperties.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java index ee10fd20c972..4c47451e891c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java @@ -43,10 +43,10 @@ public abstract class AzureServiceBusCommonProperties extends AbstractAzureAmqpC private String customEndpointAddress; /** - * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the producer, consumer or - * processor properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. Set to - * {@code false} to preserve configuration already set on the shared builder, for example the ClientOptions carrying - * TracingOptions set through an AzureServiceClientBuilderCustomizer. + * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the producer, consumer, + * or processor properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. + * Set to {@code false} to preserve configuration already set on the shared builder, for example ClientOptions + * carrying TracingOptions set through an AzureServiceClientBuilderCustomizer. */ private Boolean inheritConfiguration; From 11ee8658ddd4eef92b5555c005c7761d9fd11e18 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 10 Jul 2026 16:43:01 +0800 Subject: [PATCH 12/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../servicebus/core/properties/CommonProperties.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java index e9b381fd88f8..ef30e09b5abb 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java @@ -135,8 +135,8 @@ public Boolean getInheritConfiguration() { /** * Set whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this - * sub-client's properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior; set - * to {@code false} to preserve configuration already set on the shared builder. + * sub-client's properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. + * Set to {@code false} to preserve configuration already set on the shared builder. * @param inheritConfiguration whether to inherit the shared {@code ServiceBusClientBuilder} configuration. */ public void setInheritConfiguration(Boolean inheritConfiguration) { From 9349e3caad919ded818137cf40c2908e95e50ac9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:49:01 +0000 Subject: [PATCH 13/23] Reflow ServiceBusProcessorClientLifecycleManager JavaDoc within 120 chars Co-authored-by: moarychan <19926623+moarychan@users.noreply.github.com> --- .../ServiceBusProcessorClientLifecycleManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java index 11d83b7f8be6..8a799b64f4be 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java @@ -12,10 +12,12 @@ /** * Helper class to control the lifecycle of a {@link ServiceBusProcessorClient}. - * This class implements {@code SmartLifecycle} to auto start {@link ServiceBusProcessorClient} when the Spring Application Context starts, - * And stop the {@link ServiceBusProcessorClient} when the Spring Application Context stops. - * NOTE, there is no need to call {@link #start()} or {@link #stop()} explicitly, as the {@link ServiceBusProcessorClient} will be started and stopped automatically. - * And since the {@link ServiceBusProcessorClient} is a {@link AutoCloseable}, there is no need to call {@link ServiceBusProcessorClient#close()} explicitly. + * This class implements {@code SmartLifecycle} to auto start {@link ServiceBusProcessorClient} when the Spring + * Application Context starts, And stop the {@link ServiceBusProcessorClient} when the Spring Application Context stops. + * NOTE, there is no need to call {@link #start()} or {@link #stop()} explicitly, as the + * {@link ServiceBusProcessorClient} will be started and stopped automatically. + * And since the {@link ServiceBusProcessorClient} is a {@link AutoCloseable}, there is no need to call + * {@link ServiceBusProcessorClient#close()} explicitly. */ public class ServiceBusProcessorClientLifecycleManager implements SmartLifecycle { private final Logger logger = LoggerFactory.getLogger(ServiceBusProcessorClientLifecycleManager.class); From c31ead7fcd3f455fa2d01d3724db675e6879bb93 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 13:15:49 +0800 Subject: [PATCH 14/23] Resolve comments --- sdk/spring/CHANGELOG.md | 9 ++- .../AzureServiceBusCommonProperties.java | 16 ----- .../properties/AzureServiceBusProperties.java | 6 -- .../AzureServiceBusPropertiesTest.java | 24 ------- ...ractServiceBusSubClientBuilderFactory.java | 62 +++++++++++-------- .../ServiceBusClientCommonProperties.java | 9 --- ...erviceBusSubClientBuilderFactoryTests.java | 39 ------------ ...iceBusSenderClientBuilderFactoryTests.java | 45 ++++++++++++++ .../ServiceBusClientCommonTestProperties.java | 10 --- .../core/properties/CommonProperties.java | 16 ----- .../ConsumerPropertiesParentMerger.java | 2 - .../merger/ProcessorPropertiesMerger.java | 1 - .../ProcessorPropertiesParentMerger.java | 1 - .../merger/SenderPropertiesParentMerger.java | 2 - .../ConsumerPropertiesParentMergerTests.java | 15 ----- .../ProcessorPropertiesParentMergerTests.java | 15 ----- .../ProducerPropertiesParentMergerTests.java | 16 ----- 17 files changed, 88 insertions(+), 200 deletions(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 79f7db45291e..13874b75783e 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -10,7 +10,6 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses ([#49676](https://github.com/Azure/azure-sdk-for-java/pull/49676)). - Added support for constructing `AadB2cAuthorizationRequestResolver` with a custom `authorizationRequestBaseUri`, aligning Azure AD B2C authorization request resolution with the configurability already available for AAD. ([#49674](https://github.com/Azure/azure-sdk-for-java/pull/49674)) -- Added a new Service Bus `inherit-configuration` property (`spring.cloud.azure.servicebus[.producer|.consumer|.processor].inherit-configuration`). It defaults to `null` (treated as `true`), preserving the existing behavior. Set it to `false` to prevent the producer, consumer or processor sub-client builder from overwriting configuration already set on the shared `ServiceBusClientBuilder` (for example the `ClientOptions` carrying `TracingOptions` set through an `AzureServiceClientBuilderCustomizer`) ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). #### Breaking Changes @@ -26,6 +25,14 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Upgrade to Jackson 3 to align with Spring Boot 4 ([#49538](https://github.com/Azure/azure-sdk-for-java/issues/49538)). +### Spring Cloud Azure Service + +This section includes changes in `spring-cloud-azure-service` module. + +#### Bugs Fixed + +- Fixed the Service Bus producer, consumer and processor sub-client builders overwriting configuration already set on the underlying `ServiceBusClientBuilder` through an `AzureServiceClientBuilderCustomizer` (for example the `ClientOptions` carrying `TracingOptions`). The customizers are now applied to the underlying builder as the last step, so their configuration is preserved ([#49742](https://github.com/Azure/azure-sdk-for-java/issues/49742)). + ### Spring Messaging Azure This section includes changes in `spring-messaging-azure` module. diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java index 4c47451e891c..642cca5fdad0 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusCommonProperties.java @@ -42,14 +42,6 @@ public abstract class AzureServiceBusCommonProperties extends AbstractAzureAmqpC */ private String customEndpointAddress; - /** - * Whether the shared ServiceBusClientBuilder should inherit the configuration derived from the producer, consumer, - * or processor properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. - * Set to {@code false} to preserve configuration already set on the shared builder, for example ClientOptions - * carrying TracingOptions set through an AzureServiceClientBuilderCustomizer. - */ - private Boolean inheritConfiguration; - private String extractFqdnFromConnectionString() { if (this.connectionString == null) { return null; @@ -115,12 +107,4 @@ public String getCustomEndpointAddress() { public void setCustomEndpointAddress(String customEndpointAddress) { this.customEndpointAddress = customEndpointAddress; } - - public Boolean getInheritConfiguration() { - return inheritConfiguration; - } - - public void setInheritConfiguration(Boolean inheritConfiguration) { - this.inheritConfiguration = inheritConfiguration; - } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java index 13059d8b286e..a4f287cd8366 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusProperties.java @@ -69,7 +69,6 @@ public Producer buildProducerProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); - propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.producer.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.producer.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -77,7 +76,6 @@ public Producer buildProducerProperties() { propertyMapper.from(this.producer.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.producer.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.producer.getEntityName()).to(properties::setEntityName); - propertyMapper.from(this.producer.getInheritConfiguration()).to(properties::setInheritConfiguration); return properties; } @@ -95,7 +93,6 @@ public Consumer buildConsumerProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); - propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.consumer.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.consumer.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -103,7 +100,6 @@ public Consumer buildConsumerProperties() { propertyMapper.from(this.consumer.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.consumer.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.consumer.getEntityName()).to(properties::setEntityName); - propertyMapper.from(this.consumer.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.consumer.getSessionEnabled()).to(properties::setSessionEnabled); propertyMapper.from(this.consumer.getAutoComplete()).to(properties::setAutoComplete); @@ -129,7 +125,6 @@ public Processor buildProcessorProperties() { propertyMapper.from(this.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.getEntityName()).to(properties::setEntityName); propertyMapper.from(this.getEntityType()).to(properties::setEntityType); - propertyMapper.from(this.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.processor.getDomainName()).to(properties::setDomainName); propertyMapper.from(this.processor.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); @@ -137,7 +132,6 @@ public Processor buildProcessorProperties() { propertyMapper.from(this.processor.getConnectionString()).to(properties::setConnectionString); propertyMapper.from(this.processor.getEntityType()).to(properties::setEntityType); propertyMapper.from(this.processor.getEntityName()).to(properties::setEntityName); - propertyMapper.from(this.processor.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(this.processor.getSessionEnabled()).to(properties::setSessionEnabled); propertyMapper.from(this.processor.getAutoComplete()).to(properties::setAutoComplete); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java index 1fb5f916fe0d..aad5020e037a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesTest.java @@ -107,30 +107,6 @@ void childrenWillInheritParent() { assertEquals(customEndpoint, processor.getCustomEndpointAddress()); } - @Test - void inheritConfigurationDefaultsToNull() { - AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); - assertNull(serviceBusProperties.getInheritConfiguration()); - assertNull(serviceBusProperties.buildProducerProperties().getInheritConfiguration()); - assertNull(serviceBusProperties.buildConsumerProperties().getInheritConfiguration()); - assertNull(serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); - } - - @Test - void inheritConfigurationIsInheritedByChildrenAndOverridableByChild() { - AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); - serviceBusProperties.setInheritConfiguration(true); - - // Children inherit the namespace-level inherit-configuration value. - assertEquals(Boolean.TRUE, serviceBusProperties.buildProducerProperties().getInheritConfiguration()); - assertEquals(Boolean.TRUE, serviceBusProperties.buildConsumerProperties().getInheritConfiguration()); - assertEquals(Boolean.TRUE, serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); - - // A child-level value takes precedence over the namespace-level value. - serviceBusProperties.getProcessor().setInheritConfiguration(false); - assertEquals(Boolean.FALSE, serviceBusProperties.buildProcessorProperties().getInheritConfiguration()); - } - @Test void buildProducerPropertiesUseParent() { AzureServiceBusProperties serviceBusProperties = new AzureServiceBusProperties(); diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 6dc6ccc0040f..1c15ed102dd2 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -39,6 +39,7 @@ abstract class AbstractServiceBusSubClientBuilderFactory> serviceBusClientBuilderCustomizers; /** * Create a {@link AbstractServiceBusSubClientBuilderFactory} instance with the properties and the collection of @@ -70,11 +71,16 @@ protected AbstractServiceBusSubClientBuilderFactory(ServiceBusClientBuilder serv this.serviceBusClientBuilder = serviceBusClientBuilder; this.shareServiceBusClientBuilder = true; this.serviceBusClientBuilderFactory = null; + // The shared ServiceBusClientBuilder is configured and customized by its own factory, so there are no + // customizers for this sub-client builder factory to re-apply. + this.serviceBusClientBuilderCustomizers = null; } else { this.serviceBusClientBuilderFactory = new ServiceBusClientBuilderFactory(properties); - if (serviceBusClientBuilderCustomizers != null) { - serviceBusClientBuilderCustomizers.forEach(this.serviceBusClientBuilderFactory::addBuilderCustomizer); - } + // Remember the customizers instead of adding them to the nested factory, so they are applied to the + // underlying ServiceBusClientBuilder exactly once, as the last step in build(). This ensures they win over + // the property-derived configuration this factory redirects onto the shared builder (for example + // ClientOptions carrying TracingOptions). See #49742. + this.serviceBusClientBuilderCustomizers = serviceBusClientBuilderCustomizers; // Don't build yet - defer until first use when ApplicationContext is available this.serviceBusClientBuilder = null; this.shareServiceBusClientBuilder = false; @@ -90,6 +96,21 @@ public void setApplicationContext(ApplicationContext applicationContext) throws } } + @Override + public T build() { + // super.build() creates the sub-client builder and, in the non-shared path, lazily builds and configures the + // underlying ServiceBusClientBuilder from the properties (including the Spring identifier). The customizers are + // deliberately not applied during that step. + T builder = super.build(); + // Apply the ServiceBusClientBuilder customizers exactly once, as the last step, so they take precedence over the + // property-derived configuration redirected onto the underlying builder. See #49742. + if (!isShareServiceBusClientBuilder() && this.serviceBusClientBuilderCustomizers != null) { + this.serviceBusClientBuilderCustomizers.forEach( + customizer -> customizer.customize(getServiceBusClientBuilder())); + } + return builder; + } + @Override protected void configureCredential(T builder) { // skip to avoid overriding the parent builder's credentials. @@ -109,23 +130,10 @@ protected boolean isShareServiceBusClientBuilder() { return shareServiceBusClientBuilder; } - private boolean isInheritConfiguration() { - // Not set defaults to true, preserving the existing behavior. - return this.properties.getInheritConfiguration() == null || this.properties.getInheritConfiguration(); - } - - // In the non-shared path, the sub-client builder applies its property-derived configuration to the underlying - // ServiceBusClientBuilder when inherit-configuration is true (the default). - // Set it to false to preserve configuration already set on the shared builder (for example, ClientOptions carrying - // TracingOptions from a customizer). See #49742. - private boolean shouldConfigureServiceBusClientBuilder() { - return !isShareServiceBusClientBuilder() && isInheritConfiguration(); - } - @Override protected BiConsumer consumeProxyOptions() { return (builder, proxy) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().proxyOptions(proxy); } }; @@ -134,7 +142,7 @@ protected BiConsumer consumeProxyOptions() { @Override protected BiConsumer consumeAmqpTransportType() { return (builder, t) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().transportType(t); } }; @@ -143,7 +151,7 @@ protected BiConsumer consumeAmqpTransportType() { @Override protected BiConsumer consumeAmqpRetryOptions() { return (builder, retry) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().retryOptions(retry); } }; @@ -152,7 +160,7 @@ protected BiConsumer consumeAmqpRetryOptions() { @Override protected BiConsumer consumeClientOptions() { return (builder, client) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().clientOptions(client); } }; @@ -167,17 +175,17 @@ protected AzureProperties getAzureProperties() { protected List> getAuthenticationDescriptors(T builder) { return Arrays.asList( new NamedKeyAuthenticationDescriptor(credential -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }), new SasAuthenticationDescriptor(credential -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }), new TokenAuthenticationDescriptor(this.tokenCredentialResolver, credential -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }) @@ -187,7 +195,7 @@ protected List> getAuthenticationDescriptors(T build @Override protected BiConsumer consumeConfiguration() { return (builder, configuration) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().configuration(configuration); } }; @@ -196,7 +204,7 @@ protected BiConsumer consumeConfiguration() { @Override protected BiConsumer consumeDefaultTokenCredential() { return (builder, credential) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().credential(credential); } }; @@ -205,7 +213,7 @@ protected BiConsumer consumeDefaultTokenCredential() { @Override protected BiConsumer consumeConnectionString() { return (builder, connectionString) -> { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().connectionString(connectionString); } }; @@ -213,7 +221,7 @@ protected BiConsumer consumeConnectionString() { @Override protected void configureService(T builder) { - if (shouldConfigureServiceBusClientBuilder()) { + if (!isShareServiceBusClientBuilder()) { getServiceBusClientBuilder().fullyQualifiedNamespace(properties.getFullyQualifiedNamespace()); } } diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java index 8270d4b521cf..1de72d2ec087 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonProperties.java @@ -32,13 +32,4 @@ public interface ServiceBusClientCommonProperties extends AzureProperties, Retry * @return the custom endpoint address. */ String getCustomEndpointAddress(); - - /** - * Whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this - * sub-client's properties. When {@code null} (the default) it is treated as {@code true}, preserving the existing - * behavior. Set to {@code false} to keep configuration already present on the shared builder, for example - * {@code ClientOptions} carrying {@code TracingOptions} set through an {@code AzureServiceClientBuilderCustomizer}. - * @return whether the shared {@code ServiceBusClientBuilder} inherits this sub-client's property configuration. - */ - Boolean getInheritConfiguration(); } diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java index f06d5d051bee..5be7bf0f0e83 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactoryTests.java @@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -136,44 +135,6 @@ void connectionStringConfigured(boolean isShareServiceClientBuilder) { verify(factory.getServiceBusClientBuilder(), times(1)).connectionString(connectionString); } - @Test - void inheritConfigurationFalseSkipsConfiguringServiceBusClientBuilder() { - P properties = createMinimalServiceProperties(); - properties.setShareServiceBusClientBuilder(false); - properties.setInheritConfiguration(false); - final F factory = createClientBuilderFactoryWithMockBuilder(properties); - doReturn(false).when(factory).isShareServiceBusClientBuilder(); - ServiceBusClientBuilder rootBuilder = mock(ServiceBusClientBuilder.class); - doReturn(rootBuilder).when(factory).getServiceBusClientBuilder(); - - B builder = factory.build(); - buildClient(builder); - - // With inherit-configuration=false, the sub-client builder factory must not overwrite the shared builder, so - // that a customizer-configured builder (e.g. ClientOptions carrying TracingOptions) is preserved. See #49742. - verify(rootBuilder, times(0)).fullyQualifiedNamespace(any()); - verify(rootBuilder, times(0)).clientOptions(any()); - verify(rootBuilder, times(0)).proxyOptions(any()); - verify(rootBuilder, times(0)).retryOptions(any()); - verify(rootBuilder, times(0)).transportType(any()); - } - - @Test - void inheritConfigurationNotSetConfiguresServiceBusClientBuilder() { - P properties = createMinimalServiceProperties(); - properties.setShareServiceBusClientBuilder(false); - final F factory = createClientBuilderFactoryWithMockBuilder(properties); - doReturn(false).when(factory).isShareServiceBusClientBuilder(); - ServiceBusClientBuilder rootBuilder = mock(ServiceBusClientBuilder.class); - doReturn(rootBuilder).when(factory).getServiceBusClientBuilder(); - - B builder = factory.build(); - buildClient(builder); - - // By default (unset, treated as true) the behavior is unchanged: the shared builder is configured. - verify(rootBuilder, atLeast(1)).fullyQualifiedNamespace(properties.getFullyQualifiedNamespace()); - } - private void verifyFqdnConfigured(boolean isShareServiceClientBuilder) { P properties = createMinimalServiceProperties(); properties.setShareServiceBusClientBuilder(isShareServiceClientBuilder); diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java index 06dd1c00391e..9696a79e1d0b 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java @@ -4,10 +4,14 @@ package com.azure.spring.cloud.service.implementation.servicebus.factory; import com.azure.messaging.servicebus.ServiceBusClientBuilder; +import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; import com.azure.spring.cloud.service.implementation.servicebus.properties.ServiceBusSenderClientTestProperties; import com.azure.spring.cloud.service.servicebus.properties.ServiceBusEntityType; import org.junit.jupiter.api.Test; +import java.util.Collections; +import java.util.List; + import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -34,6 +38,27 @@ void queueConfigured() { verify(builder, times(1)).queueName("test-queue"); } + @Test + void serviceBusClientBuilderCustomizerAppliedAsLastStep() { + ServiceBusSenderClientTestProperties properties = createMinimalServiceProperties(); + properties.setShareServiceBusClientBuilder(false); + + ServiceBusClientBuilder rootBuilder = mock(ServiceBusClientBuilder.class); + @SuppressWarnings("unchecked") + AzureServiceClientBuilderCustomizer customizer = + mock(AzureServiceClientBuilderCustomizer.class); + + ServiceBusSenderClientBuilderFactory factory = + new CustomizerTestFactory(properties, Collections.singletonList(customizer), rootBuilder); + + factory.build(); + + // B-refined: in the non-shared path the ServiceBusClientBuilder customizer is applied to the underlying builder + // exactly once, as the last step of build(), so it wins over the property-derived configuration and is not + // overwritten. See #49742. + verify(customizer, times(1)).customize(rootBuilder); + } + @Override protected ServiceBusSenderClientTestProperties createMinimalServiceProperties() { ServiceBusSenderClientTestProperties properties = new ServiceBusSenderClientTestProperties(); @@ -100,4 +125,24 @@ protected ServiceBusClientBuilder getServiceBusClientBuilder() { return this.serviceBusClientBuilder; } } + + static class CustomizerTestFactory extends ServiceBusSenderClientBuilderFactory { + private final ServiceBusClientBuilder serviceBusClientBuilder; + CustomizerTestFactory(ServiceBusSenderClientTestProperties properties, + List> customizers, + ServiceBusClientBuilder serviceBusClientBuilder) { + super(properties, customizers); + this.serviceBusClientBuilder = serviceBusClientBuilder; + } + + @Override + public ServiceBusClientBuilder.ServiceBusSenderClientBuilder createBuilderInstance() { + return mock(ServiceBusClientBuilder.ServiceBusSenderClientBuilder.class); + } + + @Override + protected ServiceBusClientBuilder getServiceBusClientBuilder() { + return this.serviceBusClientBuilder; + } + } } diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java index 75d5f33f0223..2a7f915e4f8e 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/properties/ServiceBusClientCommonTestProperties.java @@ -19,7 +19,6 @@ public class ServiceBusClientCommonTestProperties extends AzureAmqpSdkProperties private String customEndpointAddress; private boolean shareServiceBusClientBuilder; - private Boolean inheritConfiguration; private String extractFqdnFromConnectionString() { if (this.connectionString == null) { @@ -94,13 +93,4 @@ public boolean isShareServiceBusClientBuilder() { public void setShareServiceBusClientBuilder(boolean shareServiceBusClientBuilder) { this.shareServiceBusClientBuilder = shareServiceBusClientBuilder; } - - @Override - public Boolean getInheritConfiguration() { - return inheritConfiguration; - } - - public void setInheritConfiguration(Boolean inheritConfiguration) { - this.inheritConfiguration = inheritConfiguration; - } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java index ef30e09b5abb..67b0295d82d1 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/core/properties/CommonProperties.java @@ -29,7 +29,6 @@ public CommonProperties() { private String entityName; private ServiceBusEntityType entityType; private String customEndpointAddress; - private Boolean inheritConfiguration; private String extractFqdnFromConnectionString() { if (this.connectionString == null) { @@ -127,19 +126,4 @@ public String getCustomEndpointAddress() { public void setCustomEndpointAddress(String customEndpointAddress) { this.customEndpointAddress = customEndpointAddress; } - - @Override - public Boolean getInheritConfiguration() { - return inheritConfiguration; - } - - /** - * Set whether the shared {@code ServiceBusClientBuilder} should inherit the configuration derived from this - * sub-client's properties. Defaults to {@code null} (treated as {@code true}), preserving the existing behavior. - * Set to {@code false} to preserve configuration already set on the shared builder. - * @param inheritConfiguration whether to inherit the shared {@code ServiceBusClientBuilder} configuration. - */ - public void setInheritConfiguration(Boolean inheritConfiguration) { - this.inheritConfiguration = inheritConfiguration; - } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java index f4e5c6a0e6d6..30581e597fb9 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMerger.java @@ -40,7 +40,6 @@ public ConsumerProperties merge(ConsumerProperties child, NamespaceProperties pa propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); - propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); // If a same property appears in both two objects, the value from the child will take precedence. copyConsumerPropertiesIfNotNull(child, properties); @@ -57,7 +56,6 @@ public static void copyConsumerPropertiesIfNotNull(ConsumerProperties source, Co propertyMapper.from(source.getEntityName()).to(target::setEntityName); propertyMapper.from(source.getEntityType()).to(target::setEntityType); propertyMapper.from(source.getCustomEndpointAddress()).to(target::setCustomEndpointAddress); - propertyMapper.from(source.getInheritConfiguration()).to(target::setInheritConfiguration); propertyMapper.from(source.getSessionEnabled()).to(target::setSessionEnabled); propertyMapper.from(source.getAutoComplete()).to(target::setAutoComplete); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java index c4433637c215..12037e8e581b 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesMerger.java @@ -47,7 +47,6 @@ public static void copyProcessorPropertiesIfNotNull(ProcessorProperties source, propertyMapper.from(source.getMaxConcurrentSessions()).to(target::setMaxConcurrentSessions); propertyMapper.from(source.getMaxConcurrentCalls()).to(target::setMaxConcurrentCalls); propertyMapper.from(source.getCustomEndpointAddress()).to(target::setCustomEndpointAddress); - propertyMapper.from(source.getInheritConfiguration()).to(target::setInheritConfiguration); propertyMapper.from(source.getSessionEnabled()).to(target::setSessionEnabled); propertyMapper.from(source.getSessionIdleTimeout()).to(target::setSessionIdleTimeout); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java index 73aa0654f185..5ed82165733c 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMerger.java @@ -38,7 +38,6 @@ public ProcessorProperties merge(ProcessorProperties child, NamespaceProperties propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); - propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); // If a same property appears in both two objects, the value from the child will take precedence. ProcessorPropertiesMerger.copyProcessorPropertiesIfNotNull(child, properties); diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java index a50796f9b01b..d0b8b651d1a9 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/main/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/SenderPropertiesParentMerger.java @@ -39,7 +39,6 @@ public ProducerProperties merge(ProducerProperties child, NamespaceProperties pa propertyMapper.from(parent.getEntityName()).to(properties::setEntityName); propertyMapper.from(parent.getEntityType()).to(properties::setEntityType); propertyMapper.from(parent.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); - propertyMapper.from(parent.getInheritConfiguration()).to(properties::setInheritConfiguration); propertyMapper.from(child.getDomainName()).to(properties::setDomainName); propertyMapper.from(child.getNamespace()).to(properties::setNamespace); @@ -47,7 +46,6 @@ public ProducerProperties merge(ProducerProperties child, NamespaceProperties pa propertyMapper.from(child.getEntityName()).to(properties::setEntityName); propertyMapper.from(child.getEntityType()).to(properties::setEntityType); propertyMapper.from(child.getCustomEndpointAddress()).to(properties::setCustomEndpointAddress); - propertyMapper.from(child.getInheritConfiguration()).to(properties::setInheritConfiguration); return properties; diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java index 5307cb7fd626..b94b240f2d4a 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ConsumerPropertiesParentMergerTests.java @@ -12,7 +12,6 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ConsumerPropertiesParentMergerTests { @@ -75,18 +74,4 @@ void childProvidedShouldUseChild() { result.getProfile().getEnvironment().getActiveDirectoryEndpoint()); assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } - - @Test - void inheritConfigurationShouldFollowParentChildPrecedence() { - NamespaceProperties parent = new NamespaceProperties(); - parent.setInheritConfiguration(true); - - // Parent value is used when the child does not set it. - assertTrue(merger.merge(new ConsumerProperties(), parent).getInheritConfiguration()); - - // Child value takes precedence over the parent value. - ConsumerProperties child = new ConsumerProperties(); - child.setInheritConfiguration(false); - assertFalse(merger.merge(child, parent).getInheritConfiguration()); - } } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java index f19534038fb3..9fe419176840 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProcessorPropertiesParentMergerTests.java @@ -14,7 +14,6 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ProcessorPropertiesParentMergerTests { @@ -83,18 +82,4 @@ void childProvidedShouldUseChild() { assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } - @Test - void inheritConfigurationShouldFollowParentChildPrecedence() { - NamespaceProperties parent = new NamespaceProperties(); - parent.setInheritConfiguration(true); - - // Parent value is used when the child does not set it. - assertTrue(merger.merge(new ProcessorProperties(), parent).getInheritConfiguration()); - - // Child value takes precedence over the parent value. - ProcessorProperties child = new ProcessorProperties(); - child.setInheritConfiguration(false); - assertFalse(merger.merge(child, parent).getInheritConfiguration()); - } - } diff --git a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java index 3051cb27ad81..a3481a376cac 100644 --- a/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java +++ b/sdk/spring/spring-messaging-azure-servicebus/src/test/java/com/azure/spring/messaging/servicebus/implementation/properties/merger/ProducerPropertiesParentMergerTests.java @@ -12,8 +12,6 @@ import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_CHINA; import static com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; public class ProducerPropertiesParentMergerTests { private final SenderPropertiesParentMerger merger = new SenderPropertiesParentMerger(); @@ -69,18 +67,4 @@ void childProvidedShouldUseChild() { assertEquals(AmqpTransportType.AMQP, result.getClient().getTransportType()); } - @Test - void inheritConfigurationShouldFollowParentChildPrecedence() { - NamespaceProperties parent = new NamespaceProperties(); - parent.setInheritConfiguration(true); - - // Parent value is used when the child does not set it. - assertTrue(merger.merge(new ProducerProperties(), parent).getInheritConfiguration()); - - // Child value takes precedence over the parent value. - ProducerProperties child = new ProducerProperties(); - child.setInheritConfiguration(false); - assertFalse(merger.merge(child, parent).getInheritConfiguration()); - } - } From 28ca8bda6fc79bb9b8d315bb9fc42081e9252f92 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 14:43:41 +0800 Subject: [PATCH 15/23] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../AbstractServiceBusSubClientBuilderFactory.java | 4 ++-- .../ServiceBusProcessorClientLifecycleManager.java | 8 ++++---- .../ServiceBusSenderClientBuilderFactoryTests.java | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 1c15ed102dd2..76c66e890d1e 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -105,8 +105,8 @@ public T build() { // Apply the ServiceBusClientBuilder customizers exactly once, as the last step, so they take precedence over the // property-derived configuration redirected onto the underlying builder. See #49742. if (!isShareServiceBusClientBuilder() && this.serviceBusClientBuilderCustomizers != null) { - this.serviceBusClientBuilderCustomizers.forEach( - customizer -> customizer.customize(getServiceBusClientBuilder())); + ServiceBusClientBuilder serviceBusClientBuilder = getServiceBusClientBuilder(); + this.serviceBusClientBuilderCustomizers.forEach(customizer -> customizer.customize(serviceBusClientBuilder)); } return builder; } diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java index 8a799b64f4be..94a2a74b1ab6 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java @@ -12,11 +12,11 @@ /** * Helper class to control the lifecycle of a {@link ServiceBusProcessorClient}. - * This class implements {@code SmartLifecycle} to auto start {@link ServiceBusProcessorClient} when the Spring - * Application Context starts, And stop the {@link ServiceBusProcessorClient} when the Spring Application Context stops. - * NOTE, there is no need to call {@link #start()} or {@link #stop()} explicitly, as the + * This class implements {@code SmartLifecycle} to automatically start {@link ServiceBusProcessorClient} when the + * Spring Application Context starts and stop it when the Spring Application Context stops. + * NOTE: There is no need to call {@link #start()} or {@link #stop()} explicitly, as the * {@link ServiceBusProcessorClient} will be started and stopped automatically. - * And since the {@link ServiceBusProcessorClient} is a {@link AutoCloseable}, there is no need to call + * Since {@link ServiceBusProcessorClient} is {@link AutoCloseable}, there is no need to call * {@link ServiceBusProcessorClient#close()} explicitly. */ public class ServiceBusProcessorClientLifecycleManager implements SmartLifecycle { diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java index 9696a79e1d0b..fee56d30af12 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java @@ -53,11 +53,10 @@ void serviceBusClientBuilderCustomizerAppliedAsLastStep() { factory.build(); - // B-refined: in the non-shared path the ServiceBusClientBuilder customizer is applied to the underlying builder - // exactly once, as the last step of build(), so it wins over the property-derived configuration and is not - // overwritten. See #49742. - verify(customizer, times(1)).customize(rootBuilder); - } + org.mockito.InOrder inOrder = org.mockito.Mockito.inOrder(rootBuilder, customizer); + inOrder.verify(rootBuilder, atLeast(1)) + .clientOptions(org.mockito.ArgumentMatchers.any(com.azure.core.util.ClientOptions.class)); + inOrder.verify(customizer, times(1)).customize(rootBuilder); @Override protected ServiceBusSenderClientTestProperties createMinimalServiceProperties() { From e6392cb435d3c824e15d5a9e9c64bd83693b4bdc Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 15:12:42 +0800 Subject: [PATCH 16/23] Improve --- .../AbstractServiceBusSubClientBuilderFactory.java | 4 ++-- .../ServiceBusSenderClientBuilderFactoryTests.java | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 76c66e890d1e..5da303329ec7 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -105,8 +105,8 @@ public T build() { // Apply the ServiceBusClientBuilder customizers exactly once, as the last step, so they take precedence over the // property-derived configuration redirected onto the underlying builder. See #49742. if (!isShareServiceBusClientBuilder() && this.serviceBusClientBuilderCustomizers != null) { - ServiceBusClientBuilder serviceBusClientBuilder = getServiceBusClientBuilder(); - this.serviceBusClientBuilderCustomizers.forEach(customizer -> customizer.customize(serviceBusClientBuilder)); + ServiceBusClientBuilder parentServiceBusClientBuilder = getServiceBusClientBuilder(); + this.serviceBusClientBuilderCustomizers.forEach(customizer -> customizer.customize(parentServiceBusClientBuilder)); } return builder; } diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java index fee56d30af12..4b80b751f791 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java @@ -3,11 +3,15 @@ package com.azure.spring.cloud.service.implementation.servicebus.factory; +import com.azure.core.util.ClientOptions; import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; import com.azure.spring.cloud.service.implementation.servicebus.properties.ServiceBusSenderClientTestProperties; import com.azure.spring.cloud.service.servicebus.properties.ServiceBusEntityType; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.InOrder; +import org.mockito.Mockito; import java.util.Collections; import java.util.List; @@ -53,10 +57,11 @@ void serviceBusClientBuilderCustomizerAppliedAsLastStep() { factory.build(); - org.mockito.InOrder inOrder = org.mockito.Mockito.inOrder(rootBuilder, customizer); + InOrder inOrder = Mockito.inOrder(rootBuilder, customizer); inOrder.verify(rootBuilder, atLeast(1)) - .clientOptions(org.mockito.ArgumentMatchers.any(com.azure.core.util.ClientOptions.class)); + .clientOptions(ArgumentMatchers.any(ClientOptions.class)); inOrder.verify(customizer, times(1)).customize(rootBuilder); + } @Override protected ServiceBusSenderClientTestProperties createMinimalServiceProperties() { From 5c357496895269ca89ff03e15b81f7735827e93e Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 15:28:22 +0800 Subject: [PATCH 17/23] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../factory/AbstractServiceBusSubClientBuilderFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 5da303329ec7..e8c0e7ec6134 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -77,7 +77,7 @@ protected AbstractServiceBusSubClientBuilderFactory(ServiceBusClientBuilder serv } else { this.serviceBusClientBuilderFactory = new ServiceBusClientBuilderFactory(properties); // Remember the customizers instead of adding them to the nested factory, so they are applied to the - // underlying ServiceBusClientBuilder exactly once, as the last step in build(). This ensures they win over + // underlying ServiceBusClientBuilder as the last step of each build() call. This ensures they win over // the property-derived configuration this factory redirects onto the shared builder (for example // ClientOptions carrying TracingOptions). See #49742. this.serviceBusClientBuilderCustomizers = serviceBusClientBuilderCustomizers; @@ -102,8 +102,8 @@ public T build() { // underlying ServiceBusClientBuilder from the properties (including the Spring identifier). The customizers are // deliberately not applied during that step. T builder = super.build(); - // Apply the ServiceBusClientBuilder customizers exactly once, as the last step, so they take precedence over the - // property-derived configuration redirected onto the underlying builder. See #49742. + // Apply the ServiceBusClientBuilder customizers as the last step of this build() call, + // so they take precedence over the property-derived configuration redirected onto the underlying builder. See #49742. if (!isShareServiceBusClientBuilder() && this.serviceBusClientBuilderCustomizers != null) { ServiceBusClientBuilder parentServiceBusClientBuilder = getServiceBusClientBuilder(); this.serviceBusClientBuilderCustomizers.forEach(customizer -> customizer.customize(parentServiceBusClientBuilder)); From f28615a70852d66de550039ec6d4ff1d7d085d9c Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 15:29:03 +0800 Subject: [PATCH 18/23] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../factory/ServiceBusSenderClientBuilderFactoryTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java index 4b80b751f791..6e117e88eec0 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java @@ -61,7 +61,8 @@ void serviceBusClientBuilderCustomizerAppliedAsLastStep() { inOrder.verify(rootBuilder, atLeast(1)) .clientOptions(ArgumentMatchers.any(ClientOptions.class)); inOrder.verify(customizer, times(1)).customize(rootBuilder); - } + inOrder.verify(rootBuilder, Mockito.never()) + .clientOptions(ArgumentMatchers.any(ClientOptions.class)); @Override protected ServiceBusSenderClientTestProperties createMinimalServiceProperties() { From 4f10f9b3f1bd29d8a696ed70adf087a26fa3619c Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 15:35:22 +0800 Subject: [PATCH 19/23] Improve --- .../factory/ServiceBusSenderClientBuilderFactoryTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java index 6e117e88eec0..77c4084c6a03 100644 --- a/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java +++ b/sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/servicebus/factory/ServiceBusSenderClientBuilderFactoryTests.java @@ -63,6 +63,7 @@ void serviceBusClientBuilderCustomizerAppliedAsLastStep() { inOrder.verify(customizer, times(1)).customize(rootBuilder); inOrder.verify(rootBuilder, Mockito.never()) .clientOptions(ArgumentMatchers.any(ClientOptions.class)); + } @Override protected ServiceBusSenderClientTestProperties createMinimalServiceProperties() { From b8cbd60d852dc4755bc163d5a447e497f6898889 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 15:45:54 +0800 Subject: [PATCH 20/23] Resolve comment --- .../factory/AbstractServiceBusSubClientBuilderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index e8c0e7ec6134..53c91d1b6a95 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -43,7 +43,7 @@ abstract class AbstractServiceBusSubClientBuilderFactory Date: Mon, 13 Jul 2026 16:00:40 +0800 Subject: [PATCH 21/23] Resolve comment --- .../factory/AbstractServiceBusSubClientBuilderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 53c91d1b6a95..8af3fe700c21 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -43,7 +43,7 @@ abstract class AbstractServiceBusSubClientBuilderFactory Date: Mon, 13 Jul 2026 16:00:59 +0800 Subject: [PATCH 22/23] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../AzureMessagingListenerAutoConfiguration.java | 12 ++++++++---- .../AbstractServiceBusSubClientBuilderFactory.java | 12 +++++++----- .../implementation/config/AzureListenerEndpoint.java | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java index 1225e1c076ea..3fc1d730e27c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/messaging/AzureMessagingListenerAutoConfiguration.java @@ -49,8 +49,10 @@ public class AzureMessagingListenerAutoConfiguration { @Configuration @ConditionalOnBean(EventHubsProcessorFactory.class) static class EventHubsConfiguration { - @Bean(name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) - @ConditionalOnMissingBean(name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @Bean( + name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @ConditionalOnMissingBean( + name = EventHubsListenerAnnotationBeanPostProcessor.DEFAULT_EVENT_HUBS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) public MessageListenerContainerFactory azureEventHubsListenerContainerFactory( EventHubsProcessorFactory eventHubsProcessorFactory, ObjectProvider> messageConverterProvider) { @@ -73,8 +75,10 @@ static class EnableEventHubsConfiguration { @Configuration @ConditionalOnBean(ServiceBusProcessorFactory.class) static class ServiceBusConfiguration { - @Bean(name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) - @ConditionalOnMissingBean(name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @Bean( + name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) + @ConditionalOnMissingBean( + name = ServiceBusListenerAnnotationBeanPostProcessor.DEFAULT_SERVICE_BUS_LISTENER_CONTAINER_FACTORY_BEAN_NAME) public MessageListenerContainerFactory azureServiceBusListenerContainerFactory( ServiceBusProcessorFactory serviceBusProcessorFactory, ObjectProvider> messageConverterProvider) { diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 8af3fe700c21..836a0550d186 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -98,15 +98,17 @@ public void setApplicationContext(ApplicationContext applicationContext) throws @Override public T build() { - // super.build() creates the sub-client builder and, in the non-shared path, lazily builds and configures the - // underlying ServiceBusClientBuilder from the properties (including the Spring identifier). The customizers are - // deliberately not applied during that step. + // super.build() creates the sub-client builder and, in the non-shared path, lazily builds and configures + // the underlying ServiceBusClientBuilder from the properties (including the Spring identifier). + // The customizers are deliberately not applied during that step. T builder = super.build(); // Apply the ServiceBusClientBuilder customizers as the last step of this build() call, - // so they take precedence over the property-derived configuration redirected onto the underlying builder. See #49742. + // so they take precedence over the property-derived configuration redirected onto the underlying builder. + // See #49742. if (!isShareServiceBusClientBuilder() && this.serviceBusClientBuilderCustomizers != null) { ServiceBusClientBuilder parentServiceBusClientBuilder = getServiceBusClientBuilder(); - this.serviceBusClientBuilderCustomizers.forEach(customizer -> customizer.customize(parentServiceBusClientBuilder)); + this.serviceBusClientBuilderCustomizers.forEach(customizer -> + customizer.customize(parentServiceBusClientBuilder)); } return builder; } diff --git a/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java b/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java index ff0226b3c7a8..3a919fccce3a 100644 --- a/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java +++ b/sdk/spring/spring-messaging-azure/src/main/java/com/azure/spring/messaging/implementation/config/AzureListenerEndpoint.java @@ -8,8 +8,8 @@ import com.azure.spring.messaging.listener.MessageListenerContainer; /** - * Model for an Azure listener endpoint. Can be used against a {@link AzureListenerConfigurer AzureListenerConfigurer} to - * register endpoints programmatically. + * Model for an Azure listener endpoint. Can be used against a {@link AzureListenerConfigurer AzureListenerConfigurer} + * to register endpoints programmatically. */ public interface AzureListenerEndpoint { From 1dac93c7dbe652ac869b33206b811a041b75c6ae Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 13 Jul 2026 16:24:36 +0800 Subject: [PATCH 23/23] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../lifecycle/ServiceBusProcessorClientLifecycleManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java index 94a2a74b1ab6..16aa4882f8c2 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/lifecycle/ServiceBusProcessorClientLifecycleManager.java @@ -13,7 +13,7 @@ /** * Helper class to control the lifecycle of a {@link ServiceBusProcessorClient}. * This class implements {@code SmartLifecycle} to automatically start {@link ServiceBusProcessorClient} when the - * Spring Application Context starts and stop it when the Spring Application Context stops. + * Spring Application Context starts and stops it when the Spring Application Context stops. * NOTE: There is no need to call {@link #start()} or {@link #stop()} explicitly, as the * {@link ServiceBusProcessorClient} will be started and stopped automatically. * Since {@link ServiceBusProcessorClient} is {@link AutoCloseable}, there is no need to call