Skip to content

Commit 21c680a

Browse files
authored
Fix bugs about token-credential-bean-name property (#47470)
1 parent 38e062e commit 21c680a

File tree

5 files changed

+175
-10
lines changed

5 files changed

+175
-10
lines changed

sdk/spring/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Release History
22

3+
## 6.1.0 (Not released)
4+
5+
### Spring Cloud Azure Autoconfigure
6+
This section includes changes in `spring-cloud-azure-autoconfigure` module.
7+
8+
#### Bugs Fixed
9+
10+
- 2 `TokenCredential` bean found in AzureServiceBusMessagingAutoConfiguration. [#47470](https://github.com/Azure/azure-sdk-for-java/pull/47470)
11+
- `spring.cloud.azure.eventhubs.credential.token-credential-bean-name` not take effect in AzureEventHubsMessagingAutoConfiguration. [#47470](https://github.com/Azure/azure-sdk-for-java/pull/47470)
12+
313
## 6.0.0 (2025-09-22)
414
- This release is compatible with Spring Boot 3.5.0-3.5.5. (Note: 3.5.x (x>5) should be supported, but they aren't tested with this release.)
515
- This release is compatible with Spring Cloud 2025.0.0. (Note: 2025.0.x(x>0) should be supported, but they aren't tested with this release.)

sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfiguration.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
package com.azure.spring.cloud.autoconfigure.implementation.eventhubs;
55

6+
import com.azure.core.credential.TokenCredential;
67
import com.azure.messaging.eventhubs.CheckpointStore;
78
import com.azure.messaging.eventhubs.EventData;
89
import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
910
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
11+
import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver;
1012
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
1113
import com.azure.spring.cloud.core.service.AzureServiceType;
1214
import com.azure.spring.messaging.ConsumerIdentifier;
@@ -27,6 +29,7 @@
2729
import org.slf4j.LoggerFactory;
2830
import org.springframework.beans.BeanUtils;
2931
import org.springframework.beans.factory.ObjectProvider;
32+
import org.springframework.beans.factory.annotation.Qualifier;
3033
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3134
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3235
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -37,6 +40,7 @@
3740
import org.springframework.context.annotation.Configuration;
3841
import org.springframework.context.annotation.Import;
3942

43+
import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME;
4044
import static com.azure.spring.cloud.core.implementation.util.AzurePropertiesUtils.copyAzureCommonProperties;
4145

4246
/**
@@ -83,10 +87,16 @@ static class ProcessorContainerConfiguration {
8387
@Bean
8488
@ConditionalOnMissingBean
8589
EventHubsProcessorFactory defaultEventHubsNamespaceProcessorFactory(
86-
NamespaceProperties properties, CheckpointStore checkpointStore,
87-
ObjectProvider<PropertiesSupplier<ConsumerIdentifier, ProcessorProperties>> suppliers) {
88-
return new DefaultEventHubsNamespaceProcessorFactory(checkpointStore, properties,
90+
NamespaceProperties properties,
91+
CheckpointStore checkpointStore,
92+
ObjectProvider<PropertiesSupplier<ConsumerIdentifier, ProcessorProperties>> suppliers,
93+
ObjectProvider<AzureTokenCredentialResolver> tokenCredentialResolvers,
94+
@Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) ObjectProvider<TokenCredential> defaultTokenCredentials) {
95+
DefaultEventHubsNamespaceProcessorFactory factory = new DefaultEventHubsNamespaceProcessorFactory(checkpointStore, properties,
8996
suppliers.getIfAvailable());
97+
factory.setDefaultCredential(defaultTokenCredentials.getIfAvailable());
98+
factory.setTokenCredentialResolver(tokenCredentialResolvers.getIfAvailable());
99+
return factory;
90100
}
91101

92102
}
@@ -98,8 +108,13 @@ static class EventHubsTemplateConfiguration {
98108
@ConditionalOnMissingBean
99109
EventHubsProducerFactory defaultEventHubsNamespaceProducerFactory(
100110
NamespaceProperties properties,
101-
ObjectProvider<PropertiesSupplier<String, ProducerProperties>> suppliers) {
102-
return new DefaultEventHubsNamespaceProducerFactory(properties, suppliers.getIfAvailable());
111+
ObjectProvider<PropertiesSupplier<String, ProducerProperties>> suppliers,
112+
ObjectProvider<AzureTokenCredentialResolver> tokenCredentialResolvers,
113+
@Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) ObjectProvider<TokenCredential> defaultTokenCredentials) {
114+
DefaultEventHubsNamespaceProducerFactory factory = new DefaultEventHubsNamespaceProducerFactory(properties, suppliers.getIfAvailable());
115+
factory.setDefaultCredential(defaultTokenCredentials.getIfAvailable());
116+
factory.setTokenCredentialResolver(tokenCredentialResolvers.getIfAvailable());
117+
return factory;
103118
}
104119

105120
@Bean

sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.slf4j.LoggerFactory;
3535
import org.springframework.beans.BeanUtils;
3636
import org.springframework.beans.factory.ObjectProvider;
37+
import org.springframework.beans.factory.annotation.Qualifier;
3738
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3839
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3940
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -44,6 +45,7 @@
4445
import org.springframework.context.annotation.Configuration;
4546
import org.springframework.context.annotation.Import;
4647

48+
import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME;
4749
import static com.azure.spring.cloud.core.implementation.util.AzurePropertiesUtils.copyAzureCommonProperties;
4850

4951

@@ -92,7 +94,7 @@ ServiceBusProcessorFactory defaultServiceBusNamespaceProcessorFactory(
9294
NamespaceProperties properties,
9395
ObjectProvider<PropertiesSupplier<ConsumerIdentifier, ProcessorProperties>> suppliers,
9496
ObjectProvider<AzureTokenCredentialResolver> tokenCredentialResolvers,
95-
ObjectProvider<TokenCredential> defaultTokenCredentials,
97+
@Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) ObjectProvider<TokenCredential> defaultTokenCredentials,
9698
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder>> clientBuilderCustomizers,
9799
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder.ServiceBusProcessorClientBuilder>> processorClientBuilderCustomizers,
98100
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder.ServiceBusSessionProcessorClientBuilder>> sessionProcessorClientBuilderCustomizers) {
@@ -115,7 +117,7 @@ ServiceBusConsumerFactory defaultServiceBusNamespaceConsumerFactory(
115117
NamespaceProperties properties,
116118
ObjectProvider<PropertiesSupplier<ConsumerIdentifier, ConsumerProperties>> suppliers,
117119
ObjectProvider<AzureTokenCredentialResolver> tokenCredentialResolvers,
118-
ObjectProvider<TokenCredential> defaultTokenCredentials,
120+
@Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) ObjectProvider<TokenCredential> defaultTokenCredentials,
119121
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder>> customizers,
120122
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder.ServiceBusSessionReceiverClientBuilder>> sessionReceiverCustomizers) {
121123
DefaultServiceBusNamespaceConsumerFactory factory = new DefaultServiceBusNamespaceConsumerFactory(properties, suppliers.getIfAvailable());
@@ -136,7 +138,7 @@ ServiceBusProducerFactory defaultServiceBusNamespaceProducerFactory(
136138
NamespaceProperties properties,
137139
ObjectProvider<PropertiesSupplier<String, ProducerProperties>> suppliers,
138140
ObjectProvider<AzureTokenCredentialResolver> tokenCredentialResolvers,
139-
ObjectProvider<TokenCredential> defaultTokenCredentials,
141+
@Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) ObjectProvider<TokenCredential> defaultTokenCredentials,
140142
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder>> clientBuilderCustomizers,
141143
ObjectProvider<AzureServiceClientBuilderCustomizer<ServiceBusClientBuilder.ServiceBusSenderClientBuilder>> senderClientBuilderCustomizers) {
142144
DefaultServiceBusNamespaceProducerFactory factory = new DefaultServiceBusNamespaceProducerFactory(properties, suppliers.getIfAvailable());

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfigurationTests.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33

44
package com.azure.spring.cloud.autoconfigure.implementation.eventhubs;
55

6+
import com.azure.core.credential.TokenCredential;
67
import com.azure.messaging.eventhubs.CheckpointStore;
8+
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
9+
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration;
710
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.configuration.TestCheckpointStore;
11+
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
12+
import com.azure.spring.cloud.core.credential.AzureCredentialResolver;
813
import com.azure.spring.messaging.eventhubs.core.EventHubsProcessorFactory;
14+
import com.azure.spring.messaging.eventhubs.core.EventHubsProducerFactory;
915
import com.azure.spring.messaging.eventhubs.core.EventHubsTemplate;
1016
import com.azure.spring.messaging.eventhubs.implementation.support.converter.EventHubsMessageConverter;
1117
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -14,10 +20,15 @@
1420
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
1521
import org.springframework.boot.test.context.FilteredClassLoader;
1622
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
26+
import java.lang.reflect.Field;
1727

1828
import static com.azure.spring.cloud.autoconfigure.implementation.eventhubs.EventHubsTestUtils.CONNECTION_STRING_FORMAT;
1929
import static org.assertj.core.api.Assertions.assertThat;
2030
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
31+
import static org.mockito.Mockito.mock;
2132

2233
class AzureEventHubsMessagingAutoConfigurationTests {
2334

@@ -121,7 +132,7 @@ void withUserProvidedObjectMapper() {
121132
.withPropertyValues("spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
122133
"spring.cloud.azure.message-converter.isolated-object-mapper=false")
123134
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
124-
.withBean("userObjectMapper", ObjectMapper.class, () -> new ObjectMapper())
135+
.withBean("userObjectMapper", ObjectMapper.class, ObjectMapper::new)
125136
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
126137
.run(context -> {
127138
assertThat(context).hasBean("userObjectMapper");
@@ -130,4 +141,61 @@ void withUserProvidedObjectMapper() {
130141
});
131142
}
132143

144+
@Test
145+
void testCustomTokenCredentialConfiguration() {
146+
this.contextRunner
147+
.withConfiguration(AutoConfigurations.of(CustomTokenCredentialConfiguration.class,
148+
AzureTokenCredentialAutoConfiguration.class,
149+
AzureGlobalPropertiesAutoConfiguration.class))
150+
.withBean(EventHubsMessageConverter.class, EventHubsMessageConverter::new)
151+
.withPropertyValues(
152+
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
153+
"spring.cloud.azure.eventhubs.credential.token-credential-bean-name=customTokenCredential"
154+
)
155+
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
156+
.run(context -> {
157+
158+
// Verify that the properties contain the correct credential bean name
159+
AzureEventHubsProperties eventHubsProperties = context.getBean(AzureEventHubsProperties.class);
160+
assertThat(eventHubsProperties).isNotNull();
161+
assertThat(eventHubsProperties.getCredential()).isNotNull();
162+
assertThat(eventHubsProperties.getCredential().getTokenCredentialBeanName())
163+
.as("The token-credential-bean-name property should be set to customTokenCredential")
164+
.isEqualTo("customTokenCredential");
165+
166+
// Verify that the custom token credential bean exists
167+
assertThat(context).hasBean("customTokenCredential");
168+
TokenCredential customCredential = context.getBean("customTokenCredential", TokenCredential.class);
169+
assertThat(customCredential).isNotNull();
170+
171+
// Verify the EventHubsProducerFactory has the tokenCredentialResolver configured
172+
assertThat(context).hasSingleBean(EventHubsProducerFactory.class);
173+
EventHubsProducerFactory producerFactory = context.getBean(EventHubsProducerFactory.class);
174+
assertThat(producerFactory).isNotNull();
175+
176+
// Verify tokenCredentialResolver resolves to the custom credential
177+
Field tokenCredentialResolverField = producerFactory.getClass().getDeclaredField("tokenCredentialResolver");
178+
tokenCredentialResolverField.setAccessible(true);
179+
Object tokenCredentialResolver = tokenCredentialResolverField.get(producerFactory);
180+
assertThat(tokenCredentialResolver).as("TokenCredentialResolver should be configured").isNotNull();
181+
182+
// Cast to AzureCredentialResolver and invoke resolve() to verify it returns customTokenCredential
183+
@SuppressWarnings("unchecked")
184+
AzureCredentialResolver<TokenCredential> resolver =
185+
(AzureCredentialResolver<TokenCredential>) tokenCredentialResolver;
186+
TokenCredential resolvedCredential = resolver.resolve(eventHubsProperties);
187+
assertThat(resolvedCredential)
188+
.as("The resolved credential should be the customTokenCredential bean")
189+
.isSameAs(customCredential);
190+
});
191+
}
192+
193+
@Configuration
194+
public static class CustomTokenCredentialConfiguration {
195+
@Bean
196+
public TokenCredential customTokenCredential() {
197+
return mock(TokenCredential.class);
198+
}
199+
}
200+
133201
}

0 commit comments

Comments
 (0)