Skip to content

Commit 8581ffa

Browse files
Add MessageConverter to AutoConfiguration (#1194)
* Add MessageConverter AutoConfiguration * Polishing Fixes #1145 --------- Co-authored-by: dongha kim <[email protected]>
1 parent 79ef4e3 commit 8581ffa

File tree

2 files changed

+63
-15
lines changed

2 files changed

+63
-15
lines changed

spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2013-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,14 +24,14 @@
2424
import io.awspring.cloud.sqs.config.SqsBootstrapConfiguration;
2525
import io.awspring.cloud.sqs.config.SqsListenerConfigurer;
2626
import io.awspring.cloud.sqs.config.SqsMessageListenerContainerFactory;
27-
import io.awspring.cloud.sqs.listener.ContainerOptionsBuilder;
2827
import io.awspring.cloud.sqs.listener.errorhandler.AsyncErrorHandler;
2928
import io.awspring.cloud.sqs.listener.errorhandler.ErrorHandler;
3029
import io.awspring.cloud.sqs.listener.interceptor.AsyncMessageInterceptor;
3130
import io.awspring.cloud.sqs.listener.interceptor.MessageInterceptor;
3231
import io.awspring.cloud.sqs.listener.SqsContainerOptionsBuilder;
3332
import io.awspring.cloud.sqs.operations.SqsTemplate;
3433
import io.awspring.cloud.sqs.operations.SqsTemplateBuilder;
34+
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
3535
import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
3636
import org.springframework.beans.factory.ObjectProvider;
3737
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -46,13 +46,15 @@
4646
import org.springframework.context.annotation.Import;
4747
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
4848
import software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder;
49+
import software.amazon.awssdk.services.sqs.model.Message;
4950

5051
/**
5152
* {@link EnableAutoConfiguration Auto-configuration} for SQS integration.
5253
*
5354
* @author Tomaz Fernandes
5455
* @author Maciej Walkowiak
5556
* @author Wei Jiang
57+
* @author Dongha Kim
5658
* @since 3.0
5759
*/
5860
@AutoConfiguration
@@ -80,10 +82,9 @@ public SqsAsyncClient sqsAsyncClient(AwsClientBuilderConfigurer awsClientBuilder
8082

8183
@ConditionalOnMissingBean
8284
@Bean
83-
public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient, ObjectProvider<ObjectMapper> objectMapperProvider) {
84-
SqsTemplateBuilder builder = SqsTemplate.builder().sqsAsyncClient(sqsAsyncClient);
85-
objectMapperProvider
86-
.ifAvailable(om -> builder.configureDefaultConverter(converter -> converter.setObjectMapper(om)));
85+
public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient, ObjectProvider<ObjectMapper> objectMapperProvider, MessagingMessageConverter<Message> messageConverter) {
86+
SqsTemplateBuilder builder = SqsTemplate.builder().sqsAsyncClient(sqsAsyncClient).messageConverter(messageConverter);
87+
objectMapperProvider.ifAvailable(om -> setMapperToConverter(messageConverter, om));
8788
if (sqsProperties.getQueueNotFoundStrategy() != null) {
8889
builder.configure((options) -> options.queueNotFoundStrategy(sqsProperties.getQueueNotFoundStrategy()));
8990
}
@@ -97,27 +98,34 @@ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFac
9798
ObjectProvider<ErrorHandler<Object>> errorHandler,
9899
ObjectProvider<AsyncMessageInterceptor<Object>> asyncInterceptors,
99100
ObjectProvider<MessageInterceptor<Object>> interceptors,
100-
ObjectProvider<ObjectMapper> objectMapperProvider) {
101+
ObjectProvider<ObjectMapper> objectMapperProvider,
102+
MessagingMessageConverter<?> messagingMessageConverter) {
101103

102104
SqsMessageListenerContainerFactory<Object> factory = new SqsMessageListenerContainerFactory<>();
103-
factory.configure(this::configureContainerOptions);
105+
factory.configure(this::configureProperties);
104106
sqsAsyncClient.ifAvailable(factory::setSqsAsyncClient);
105107
asyncErrorHandler.ifAvailable(factory::setErrorHandler);
106108
errorHandler.ifAvailable(factory::setErrorHandler);
107109
interceptors.forEach(factory::addMessageInterceptor);
108110
asyncInterceptors.forEach(factory::addMessageInterceptor);
109-
objectMapperProvider.ifAvailable(objectMapper -> setObjectMapper(factory, objectMapper));
111+
objectMapperProvider.ifAvailable(om -> setMapperToConverter(messagingMessageConverter, om));
112+
factory.configure(options -> options.messageConverter(messagingMessageConverter));
110113
return factory;
111114
}
112115

113-
private void setObjectMapper(SqsMessageListenerContainerFactory<Object> factory, ObjectMapper objectMapper) {
114-
// Object Mapper for early deserialization in MessageSource
115-
var messageConverter = new SqsMessagingMessageConverter();
116-
messageConverter.setObjectMapper(objectMapper);
117-
factory.configure(options -> options.messageConverter(messageConverter));
116+
private void setMapperToConverter(MessagingMessageConverter<?> messagingMessageConverter, ObjectMapper om) {
117+
if (messagingMessageConverter instanceof SqsMessagingMessageConverter sqsConverter) {
118+
sqsConverter.setObjectMapper(om);
119+
}
120+
}
121+
122+
@ConditionalOnMissingBean
123+
@Bean
124+
public MessagingMessageConverter<Message> messageConverter() {
125+
return new SqsMessagingMessageConverter();
118126
}
119127

120-
private void configureContainerOptions(SqsContainerOptionsBuilder options) {
128+
private void configureProperties(SqsContainerOptionsBuilder options) {
121129
PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
122130
mapper.from(this.sqsProperties.getQueueNotFoundStrategy()).to(options::queueNotFoundStrategy);
123131
mapper.from(this.sqsProperties.getListener().getMaxConcurrentMessages()).to(options::maxConcurrentMessages);

spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfigurationTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@
3030
import io.awspring.cloud.sqs.config.EndpointRegistrar;
3131
import io.awspring.cloud.sqs.config.SqsBootstrapConfiguration;
3232
import io.awspring.cloud.sqs.config.SqsMessageListenerContainerFactory;
33+
import io.awspring.cloud.sqs.listener.AbstractContainerOptions;
3334
import io.awspring.cloud.sqs.listener.ContainerOptions;
3435
import io.awspring.cloud.sqs.listener.ContainerOptionsBuilder;
3536
import io.awspring.cloud.sqs.listener.QueueNotFoundStrategy;
37+
import io.awspring.cloud.sqs.listener.MessageListenerContainerRegistry;
38+
import io.awspring.cloud.sqs.listener.SqsContainerOptions;
3639
import io.awspring.cloud.sqs.listener.errorhandler.AsyncErrorHandler;
3740
import io.awspring.cloud.sqs.listener.interceptor.AsyncMessageInterceptor;
3841
import io.awspring.cloud.sqs.operations.SqsTemplate;
42+
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
3943
import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
4044
import java.net.URI;
4145
import java.time.Duration;
@@ -56,6 +60,7 @@
5660
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
5761
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
5862
import software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder;
63+
import software.amazon.awssdk.services.sqs.model.Message;
5964

6065
/**
6166
* Tests for {@link SqsAutoConfiguration}.
@@ -66,6 +71,7 @@
6671
class SqsAutoConfigurationTest {
6772

6873
private static final String CUSTOM_OBJECT_MAPPER_BEAN_NAME = "customObjectMapper";
74+
private static final String CUSTOM_MESSAGE_CONVERTER_BEAN_NAME = "customMessageConverter";
6975

7076
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
7177
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
@@ -219,6 +225,30 @@ void configuresObjectMapper() {
219225
});
220226
}
221227

228+
@Test
229+
void configuresMessageConverter() {
230+
this.contextRunner.withPropertyValues("spring.cloud.aws.sqs.enabled:true")
231+
.withUserConfiguration(ObjectMapperConfiguration.class, MessageConverterConfiguration.class)
232+
.run(context -> {
233+
SqsTemplate sqsTemplate = context.getBean("sqsTemplate", SqsTemplate.class);
234+
SqsMessageListenerContainerFactory<?> factory = context.getBean("defaultSqsListenerContainerFactory", SqsMessageListenerContainerFactory.class);
235+
ObjectMapper objectMapper = context.getBean(CUSTOM_OBJECT_MAPPER_BEAN_NAME, ObjectMapper.class);
236+
SqsMessagingMessageConverter converter = context.getBean(CUSTOM_MESSAGE_CONVERTER_BEAN_NAME, SqsMessagingMessageConverter.class);
237+
assertThat(converter.getPayloadMessageConverter())
238+
.extracting("converters")
239+
.asList()
240+
.filteredOn(conv -> conv instanceof MappingJackson2MessageConverter)
241+
.first()
242+
.extracting("objectMapper")
243+
.isEqualTo(objectMapper);
244+
assertThat(sqsTemplate).extracting("messageConverter").isEqualTo(converter);
245+
assertThat(factory)
246+
.extracting("containerOptionsBuilder")
247+
.extracting("messageConverter")
248+
.isEqualTo(converter);
249+
});
250+
}
251+
222252
@Configuration(proxyBeanMethods = false)
223253
static class CustomComponentsConfiguration {
224254

@@ -246,6 +276,16 @@ ObjectMapper objectMapper() {
246276

247277
}
248278

279+
@Configuration(proxyBeanMethods = false)
280+
static class MessageConverterConfiguration {
281+
282+
@Bean(name = CUSTOM_MESSAGE_CONVERTER_BEAN_NAME)
283+
MessagingMessageConverter<Message> messageConverter() {
284+
return new SqsMessagingMessageConverter();
285+
}
286+
287+
}
288+
249289
@Configuration(proxyBeanMethods = false)
250290
static class CustomAwsAsyncClientConfig {
251291

0 commit comments

Comments
 (0)