Skip to content

Commit e6eb8dd

Browse files
authored
Fix IllegalArgumentException: Subscription cannot be null (Azure#40283)
* Fix IllegalArgumentException: Subscription cannot be null * update CHANGELOG.md
1 parent bca73d9 commit e6eb8dd

File tree

10 files changed

+243
-37
lines changed

10 files changed

+243
-37
lines changed

eng/code-quality-reports/src/main/resources/revapi/revapi.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,13 @@
469469
"code": "java\\.annotation\\.removed",
470470
"old": ".*? com\\.azure\\.monitor\\.query.*",
471471
"justification": "Removing Jackson annotations from Monitor Query in transition to stream-style."
472+
},
473+
{
474+
"regex": true,
475+
"code": "java.annotation.removed",
476+
"old": ".*? com.azure.storage.file.share.models.*",
477+
"new": ".*? com.azure.storage.file.share.models.*",
478+
"justification": "Removing Jackson annotations from Monitor Query in transition to stream-style."
472479
}
473480
]
474481
}

sdk/spring/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# Release History
2+
## 4.19.0-beta.1 (Unreleased)
3+
4+
### Spring Cloud Azure Autoconfigure
5+
This section includes changes in `spring-cloud-azure-autoconfigure` module.
6+
7+
### Bugs Fixed
8+
- Fixed `IllegalArgumentException: Subscription cannot be null` error when only configured one subscription name of `AzureServiceBusConsumerClient` or `AzureServiceBusProcessorClient` [#40283](https://github.com/Azure/azure-sdk-for-java/pull/40283).
29

310
## 5.12.0 (2024-05-09)
411
- This release is compatible with Spring Boot 3.0.0-3.0.13, 3.1.0-3.1.8, 3.2.0-3.2.5. (Note: 3.0.x (x>13), 3.1.y (y>8) and 3.2.z (z>5) should be supported, but they aren't tested with this release.)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
5+
6+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.utils.AzureServiceBusPropertiesUtils;
7+
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
8+
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
9+
import org.springframework.context.annotation.ConditionContext;
10+
import org.springframework.core.type.AnnotatedTypeMetadata;
11+
12+
public class AzureServiceBusConsumerCondition extends SpringBootCondition {
13+
14+
@Override
15+
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
16+
17+
String entityType = AzureServiceBusPropertiesUtils.getServiceBusProperties(context, "consumer.entity-type", "entity-type");
18+
String consumerSubscriptionName = AzureServiceBusPropertiesUtils.getServiceBusProperties(context, "consumer.subscription-name");
19+
20+
if ("queue".equalsIgnoreCase(entityType)) {
21+
return ConditionOutcome.match();
22+
}
23+
24+
if ("topic".equalsIgnoreCase(entityType)) {
25+
if (consumerSubscriptionName != null) {
26+
return ConditionOutcome.match();
27+
} else {
28+
return ConditionOutcome.noMatch("spring.cloud.azure.servicebus.consumer.subscription-name is missing.");
29+
}
30+
}
31+
32+
return ConditionOutcome.noMatch("Entity type should be queue/topic.");
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
5+
6+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.utils.AzureServiceBusPropertiesUtils;
7+
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
8+
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
9+
import org.springframework.context.annotation.ConditionContext;
10+
import org.springframework.core.type.AnnotatedTypeMetadata;
11+
12+
public class AzureServiceBusProcessorCondition extends SpringBootCondition {
13+
14+
@Override
15+
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
16+
17+
String entityType = AzureServiceBusPropertiesUtils.getServiceBusProperties(context, "processor.entity-type", "entity-type");
18+
String processorSubscriptionName = AzureServiceBusPropertiesUtils.getServiceBusProperties(context, "processor.subscription-name");
19+
20+
if ("queue".equalsIgnoreCase(entityType)) {
21+
return ConditionOutcome.match();
22+
}
23+
24+
if ("topic".equalsIgnoreCase(entityType)) {
25+
if (processorSubscriptionName != null) {
26+
return ConditionOutcome.match();
27+
} else {
28+
return ConditionOutcome.noMatch("spring.cloud.azure.servicebus.processor.subscription-name is missing.");
29+
}
30+
}
31+
32+
return ConditionOutcome.noMatch("Entity type should be queue/topic.");
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus.utils;
5+
6+
import org.springframework.context.annotation.ConditionContext;
7+
import org.springframework.core.env.Environment;
8+
9+
public final class AzureServiceBusPropertiesUtils {
10+
11+
private AzureServiceBusPropertiesUtils() {
12+
}
13+
14+
public static String getServiceBusProperties(ConditionContext context, String... names) {
15+
Environment environment = context.getEnvironment();
16+
String property = null;
17+
for (String name : names) {
18+
property = environment.getProperty("spring.cloud.azure.servicebus." + name);
19+
if (property != null) {
20+
break;
21+
}
22+
}
23+
return property;
24+
}
25+
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.azure.messaging.servicebus.ServiceBusSessionReceiverAsyncClient;
1010
import com.azure.messaging.servicebus.ServiceBusSessionReceiverClient;
1111
import com.azure.spring.cloud.autoconfigure.condition.ConditionalOnAnyProperty;
12+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusConsumerCondition;
1213
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
1314
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
1415
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
@@ -20,6 +21,7 @@
2021
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2122
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2223
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Conditional;
2325
import org.springframework.context.annotation.Configuration;
2426
import org.springframework.context.annotation.Import;
2527
import org.springframework.util.StringUtils;
@@ -34,12 +36,12 @@
3436
AzureServiceBusConsumerClientConfiguration.SessionConsumerClientConfiguration.class,
3537
AzureServiceBusConsumerClientConfiguration.NoneSessionConsumerClientConfiguration.class
3638
})
39+
@Conditional(AzureServiceBusConsumerCondition.class)
3740
class AzureServiceBusConsumerClientConfiguration {
3841

3942
@Configuration(proxyBeanMethods = false)
4043
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.consumer.session-enabled", havingValue = "false",
4144
matchIfMissing = true)
42-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "entity-type", "consumer.entity-type" })
4345
static class NoneSessionConsumerClientConfiguration {
4446

4547
@Bean
@@ -88,7 +90,6 @@ public ServiceBusReceiverClient serviceBusReceiverClient(
8890

8991
@Configuration(proxyBeanMethods = false)
9092
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.consumer.session-enabled", havingValue = "true")
91-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "entity-type", "consumer.entity-type" })
9293
static class SessionConsumerClientConfiguration {
9394

9495
@Bean

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
77
import com.azure.messaging.servicebus.ServiceBusProcessorClient;
88
import com.azure.spring.cloud.autoconfigure.condition.ConditionalOnAnyProperty;
9+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusProcessorCondition;
910
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
1011
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
1112
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
@@ -22,6 +23,7 @@
2223
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2425
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Conditional;
2527
import org.springframework.context.annotation.Configuration;
2628
import org.springframework.context.annotation.Import;
2729
import org.springframework.util.StringUtils;
@@ -36,6 +38,7 @@
3638
AzureServiceBusProcessorClientConfiguration.SessionProcessorClientConfiguration.class,
3739
AzureServiceBusProcessorClientConfiguration.NoneSessionProcessorClientConfiguration.class
3840
})
41+
@Conditional(AzureServiceBusProcessorCondition.class)
3942
class AzureServiceBusProcessorClientConfiguration {
4043

4144
@Bean
@@ -51,7 +54,6 @@ ServiceBusProcessorClientLifecycleManager processorClientLifecycleManager(Servic
5154
@Configuration(proxyBeanMethods = false)
5255
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.processor.session-enabled", havingValue = "false",
5356
matchIfMissing = true)
54-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "entity-type", "processor.entity-type" })
5557
static class NoneSessionProcessorClientConfiguration {
5658

5759
@Bean
@@ -102,7 +104,6 @@ public ServiceBusProcessorClient serviceBusProcessorClient(
102104

103105
@Configuration(proxyBeanMethods = false)
104106
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.processor.session-enabled", havingValue = "true")
105-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "entity-type", "processor.entity-type" })
106107
static class SessionProcessorClientConfiguration {
107108

108109
@Bean

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/servicebus/AzureServiceBusAutoConfigurationTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider;
1414
import com.azure.spring.cloud.core.provider.RetryOptionsProvider;
1515
import com.azure.spring.cloud.service.implementation.servicebus.factory.ServiceBusClientBuilderFactory;
16+
import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusErrorHandler;
17+
import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusRecordMessageListener;
1618
import com.azure.spring.cloud.service.servicebus.properties.ServiceBusEntityType;
1719
import org.junit.jupiter.api.Test;
1820
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -264,5 +266,39 @@ void configurationPropertiesShouldBind() {
264266
});
265267
}
266268

269+
@Test
270+
void processorSubscriptionNameShouldConfigureProcessorClient() {
271+
this.contextRunner
272+
.withPropertyValues(
273+
"spring.cloud.azure.servicebus.namespace=test-namespace",
274+
"spring.cloud.azure.servicebus.entity-name=test-topic",
275+
"spring.cloud.azure.servicebus.entity-type=topic",
276+
"spring.cloud.azure.servicebus.processor.subscription-name=sub"
277+
)
278+
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
279+
.withBean(ServiceBusRecordMessageListener.class, () -> messageContext -> { })
280+
.withBean(ServiceBusErrorHandler.class, () -> errorContext -> { })
281+
.run(context -> {
282+
assertThat(context).doesNotHaveBean(AzureServiceBusConsumerClientConfiguration.class);
283+
assertThat(context).hasSingleBean(AzureServiceBusProcessorClientConfiguration.class);
284+
});
285+
}
267286

287+
@Test
288+
void consumerSubscriptionNameShouldConfigureConsumerClient() {
289+
this.contextRunner
290+
.withPropertyValues(
291+
"spring.cloud.azure.servicebus.namespace=test-namespace",
292+
"spring.cloud.azure.servicebus.entity-name=test-topic",
293+
"spring.cloud.azure.servicebus.entity-type=topic",
294+
"spring.cloud.azure.servicebus.consumer.subscription-name=sub"
295+
)
296+
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
297+
.withBean(ServiceBusRecordMessageListener.class, () -> messageContext -> { })
298+
.withBean(ServiceBusErrorHandler.class, () -> errorContext -> { })
299+
.run(context -> {
300+
assertThat(context).doesNotHaveBean(AzureServiceBusProcessorClientConfiguration.class);
301+
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class);
302+
});
303+
}
268304
}

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/servicebus/AzureServiceBusConsumerClientConfigurationTests.java

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import static com.azure.spring.cloud.autoconfigure.servicebus.ServiceBusTestUtils.CONNECTION_STRING_FORMAT;
1616
import static org.assertj.core.api.Assertions.assertThat;
17-
import static org.junit.jupiter.api.Assertions.assertThrows;
1817

1918
class AzureServiceBusConsumerClientConfigurationTests {
2019

@@ -44,33 +43,34 @@ void entityNameProvidedShouldConfigure() {
4443
}
4544

4645
@Test
47-
void entityTypeProvidedShouldConfigure() {
46+
void queueNameProvidedShouldConfigure() {
4847
ServiceBusClientBuilder serviceBusClientBuilder = new ServiceBusClientBuilder();
4948
serviceBusClientBuilder.connectionString(String.format(CONNECTION_STRING_FORMAT, "test-namespace"));
5049

5150
contextRunner
5251
.withPropertyValues(
5352
"spring.cloud.azure.servicebus.entity-name=test-queue",
54-
"spring.cloud.azure.servicebus.consumer.entity-name=test-queue"
53+
"spring.cloud.azure.servicebus.entity-type=queue"
5554
)
5655
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
5756
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
5857
.run(context -> {
5958
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class);
60-
assertThat(context).doesNotHaveBean(AzureServiceBusConsumerClientConfiguration.NoneSessionConsumerClientConfiguration.class);
59+
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.NoneSessionConsumerClientConfiguration.class);
6160
assertThat(context).doesNotHaveBean(AzureServiceBusConsumerClientConfiguration.SessionConsumerClientConfiguration.class);
6261
});
6362
}
6463

6564
@Test
66-
void queueNameProvidedShouldConfigure() {
65+
void subscriptionNameProvidedShouldConfigure() {
6766
ServiceBusClientBuilder serviceBusClientBuilder = new ServiceBusClientBuilder();
6867
serviceBusClientBuilder.connectionString(String.format(CONNECTION_STRING_FORMAT, "test-namespace"));
6968

7069
contextRunner
7170
.withPropertyValues(
72-
"spring.cloud.azure.servicebus.entity-name=test-queue",
73-
"spring.cloud.azure.servicebus.entity-type=queue"
71+
"spring.cloud.azure.servicebus.consumer.entity-name=test-topic",
72+
"spring.cloud.azure.servicebus.consumer.subscription-name=test-sub",
73+
"spring.cloud.azure.servicebus.consumer.entity-type=topic"
7474
)
7575
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
7676
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
@@ -82,23 +82,49 @@ void queueNameProvidedShouldConfigure() {
8282
}
8383

8484
@Test
85-
void subscriptionNameProvidedShouldConfigure() {
85+
void noSubscriptionNameShouldConfigureForQueue() {
8686
ServiceBusClientBuilder serviceBusClientBuilder = new ServiceBusClientBuilder();
8787
serviceBusClientBuilder.connectionString(String.format(CONNECTION_STRING_FORMAT, "test-namespace"));
8888

8989
contextRunner
9090
.withPropertyValues(
91-
"spring.cloud.azure.servicebus.consumer.entity-name=test-topic",
92-
"spring.cloud.azure.servicebus.consumer.subscription-name=test-sub",
93-
"spring.cloud.azure.servicebus.consumer.entity-type=topic"
91+
"spring.cloud.azure.servicebus.entity-name=test-queue",
92+
"spring.cloud.azure.servicebus.entity-type=queue"
9493
)
9594
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
9695
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
97-
.run(context -> {
98-
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class);
99-
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.NoneSessionConsumerClientConfiguration.class);
100-
assertThat(context).doesNotHaveBean(AzureServiceBusConsumerClientConfiguration.SessionConsumerClientConfiguration.class);
101-
});
96+
.run(context -> assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class));
97+
}
98+
99+
@Test
100+
void noSubscriptionNameShouldNotConfigureForTopic() {
101+
ServiceBusClientBuilder serviceBusClientBuilder = new ServiceBusClientBuilder();
102+
serviceBusClientBuilder.connectionString(String.format(CONNECTION_STRING_FORMAT, "test-namespace"));
103+
104+
contextRunner
105+
.withPropertyValues(
106+
"spring.cloud.azure.servicebus.entity-name=test-topic",
107+
"spring.cloud.azure.servicebus.entity-type=topic"
108+
)
109+
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
110+
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
111+
.run(context -> assertThat(context).doesNotHaveBean(AzureServiceBusConsumerClientConfiguration.class));
112+
}
113+
114+
@Test
115+
void subscriptionNameShouldConfigureForTopic() {
116+
ServiceBusClientBuilder serviceBusClientBuilder = new ServiceBusClientBuilder();
117+
serviceBusClientBuilder.connectionString(String.format(CONNECTION_STRING_FORMAT, "test-namespace"));
118+
119+
contextRunner
120+
.withPropertyValues(
121+
"spring.cloud.azure.servicebus.entity-name=test-topic",
122+
"spring.cloud.azure.servicebus.entity-type=topic",
123+
"spring.cloud.azure.servicebus.consumer.subscription-name=test-sub"
124+
)
125+
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
126+
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
127+
.run(context -> assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class));
102128
}
103129

104130
@Test
@@ -113,7 +139,7 @@ void subscriptionNameProvidedShouldNotConfigure() {
113139
)
114140
.withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
115141
.withBean(ServiceBusClientBuilder.class, () -> serviceBusClientBuilder)
116-
.run(context -> assertThrows(IllegalStateException.class, () -> context.getBean(AzureServiceBusConsumerClientConfiguration.class)));
142+
.run(context -> assertThat(context).doesNotHaveBean(AzureServiceBusProcessorClientConfiguration.class));
117143
}
118144

119145
@Test

0 commit comments

Comments
 (0)