diff --git a/spring-cloud-aws-autoconfigure/pom.xml b/spring-cloud-aws-autoconfigure/pom.xml
index be89828598..4b94b4cb17 100644
--- a/spring-cloud-aws-autoconfigure/pom.xml
+++ b/spring-cloud-aws-autoconfigure/pom.xml
@@ -76,6 +76,11 @@
spring-cloud-aws-ses
true
+
+ tools.jackson.core
+ jackson-databind
+ true
+
io.awspring.cloud
spring-cloud-aws-sns
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
index 2d43ebdbe3..ff5088908b 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
@@ -21,19 +21,15 @@
import io.awspring.cloud.autoconfigure.core.AwsConnectionDetails;
import io.awspring.cloud.autoconfigure.core.AwsProperties;
import io.awspring.cloud.autoconfigure.s3.properties.S3Properties;
-import io.awspring.cloud.s3.InMemoryBufferingS3OutputStreamProvider;
-import io.awspring.cloud.s3.Jackson2JsonS3ObjectConverter;
-import io.awspring.cloud.s3.PropertiesS3ObjectContentTypeResolver;
-import io.awspring.cloud.s3.S3ObjectContentTypeResolver;
-import io.awspring.cloud.s3.S3ObjectConverter;
-import io.awspring.cloud.s3.S3Operations;
-import io.awspring.cloud.s3.S3OutputStreamProvider;
-import io.awspring.cloud.s3.S3ProtocolResolver;
-import io.awspring.cloud.s3.S3Template;
+import io.awspring.cloud.s3.*;
import java.util.Optional;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.*;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
@@ -49,6 +45,7 @@
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.encryption.s3.S3EncryptionClient;
+import tools.jackson.databind.json.JsonMapper;
/**
* {@link AutoConfiguration} for {@link S3Client} and {@link S3ProtocolResolver}.
@@ -124,11 +121,50 @@ else if (awsProperties.getEndpoint() != null) {
return builder.build();
}
+ @Bean
+ @ConditionalOnMissingBean
+ S3Client s3Client(S3ClientBuilder s3ClientBuilder) {
+ return s3ClientBuilder.build();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ S3OutputStreamProvider inMemoryBufferingS3StreamProvider(S3Client s3Client,
+ Optional contentTypeResolver) {
+ return new InMemoryBufferingS3OutputStreamProvider(s3Client,
+ contentTypeResolver.orElseGet(PropertiesS3ObjectContentTypeResolver::new));
+ }
+
@Conditional(S3EncryptionConditional.class)
@ConditionalOnClass(name = "software.amazon.encryption.s3.S3EncryptionClient")
@Configuration
public static class S3EncryptionConfiguration {
+ private static void configureEncryptionProperties(S3Properties properties,
+ ObjectProvider rsaProvider, ObjectProvider aesProvider,
+ S3EncryptionClient.Builder builder) {
+ PropertyMapper propertyMapper = PropertyMapper.get();
+ var encryptionProperties = properties.getEncryption();
+
+ propertyMapper.from(encryptionProperties::isEnableDelayedAuthenticationMode)
+ .to(builder::enableDelayedAuthenticationMode);
+ propertyMapper.from(encryptionProperties::isEnableLegacyUnauthenticatedModes)
+ .to(builder::enableLegacyUnauthenticatedModes);
+ propertyMapper.from(encryptionProperties::isEnableMultipartPutObject).to(builder::enableMultipartPutObject);
+
+ if (!StringUtils.hasText(properties.getEncryption().getKeyId())) {
+ if (aesProvider.getIfAvailable() != null) {
+ builder.aesKey(aesProvider.getObject().generateSecretKey());
+ }
+ else {
+ builder.rsaKeyPair(rsaProvider.getObject().generateKeyPair());
+ }
+ }
+ else {
+ propertyMapper.from(encryptionProperties::getKeyId).to(builder::kmsKeyId);
+ }
+ }
+
@Bean
@ConditionalOnMissingBean
S3Client s3EncryptionClient(S3EncryptionClient.Builder s3EncryptionBuilder, S3ClientBuilder s3ClientBuilder) {
@@ -154,55 +190,28 @@ S3EncryptionClient.Builder s3EncrpytionClientBuilder(S3Properties properties,
configureEncryptionProperties(properties, rsaProvider, aesProvider, builder);
return builder;
}
+ }
- private static void configureEncryptionProperties(S3Properties properties,
- ObjectProvider rsaProvider, ObjectProvider aesProvider,
- S3EncryptionClient.Builder builder) {
- PropertyMapper propertyMapper = PropertyMapper.get();
- var encryptionProperties = properties.getEncryption();
-
- propertyMapper.from(encryptionProperties::isEnableDelayedAuthenticationMode)
- .to(builder::enableDelayedAuthenticationMode);
- propertyMapper.from(encryptionProperties::isEnableLegacyUnauthenticatedModes)
- .to(builder::enableLegacyUnauthenticatedModes);
- propertyMapper.from(encryptionProperties::isEnableMultipartPutObject).to(builder::enableMultipartPutObject);
+ @Configuration
+ @AutoConfigureAfter(Jackson2JsonS3ObjectConverterConfiguration.class)
+ @ConditionalOnClass(value = ObjectMapper.class)
+ static class LegacyJackson2JsonS3ObjectConverterConfiguration {
- if (!StringUtils.hasText(properties.getEncryption().getKeyId())) {
- if (aesProvider.getIfAvailable() != null) {
- builder.aesKey(aesProvider.getObject().generateSecretKey());
- }
- else {
- builder.rsaKeyPair(rsaProvider.getObject().generateKeyPair());
- }
- }
- else {
- propertyMapper.from(encryptionProperties::getKeyId).to(builder::kmsKeyId);
- }
+ @ConditionalOnMissingBean
+ @Bean
+ S3ObjectConverter s3ObjectConverter(Optional objectMapper) {
+ return new LegacyJackson2JsonS3ObjectConverter(objectMapper.orElseGet(ObjectMapper::new));
}
}
- @Bean
- @ConditionalOnMissingBean
- S3Client s3Client(S3ClientBuilder s3ClientBuilder) {
- return s3ClientBuilder.build();
- }
-
@Configuration
- @ConditionalOnClass(ObjectMapper.class)
+ @ConditionalOnClass(value = JsonMapper.class)
static class Jackson2JsonS3ObjectConverterConfiguration {
@ConditionalOnMissingBean
@Bean
- S3ObjectConverter s3ObjectConverter(Optional objectMapper) {
- return new Jackson2JsonS3ObjectConverter(objectMapper.orElseGet(ObjectMapper::new));
+ S3ObjectConverter s3ObjectConverter(Optional jsonMapper) {
+ return new Jackson2JsonS3ObjectConverter(jsonMapper.orElseGet(JsonMapper::new));
}
}
-
- @Bean
- @ConditionalOnMissingBean
- S3OutputStreamProvider inMemoryBufferingS3StreamProvider(S3Client s3Client,
- Optional contentTypeResolver) {
- return new InMemoryBufferingS3OutputStreamProvider(s3Client,
- contentTypeResolver.orElseGet(PropertiesS3ObjectContentTypeResolver::new));
- }
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
index 07fa547f7f..caacf30442 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sqs/SqsAutoConfiguration.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.autoconfigure.sqs;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.autoconfigure.AwsAsyncClientCustomizer;
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
import io.awspring.cloud.autoconfigure.core.AwsConnectionDetails;
@@ -31,8 +30,12 @@
import io.awspring.cloud.sqs.listener.interceptor.MessageInterceptor;
import io.awspring.cloud.sqs.operations.SqsTemplate;
import io.awspring.cloud.sqs.operations.SqsTemplateBuilder;
+import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.JacksonJsonMessageConverterFactory;
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import io.awspring.cloud.sqs.support.observation.SqsListenerObservation;
import io.awspring.cloud.sqs.support.observation.SqsTemplateObservation;
import io.micrometer.observation.ObservationRegistry;
@@ -49,6 +52,7 @@
import org.springframework.context.annotation.Import;
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
import software.amazon.awssdk.services.sqs.model.Message;
+import tools.jackson.databind.json.JsonMapper;
/**
* {@link EnableAutoConfiguration Auto-configuration} for SQS integration.
@@ -87,7 +91,8 @@ public SqsAsyncClient sqsAsyncClient(AwsClientBuilderConfigurer awsClientBuilder
@ConditionalOnMissingBean
@Bean
- public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient, ObjectProvider objectMapperProvider,
+ public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient,
+ ObjectProvider objectMapperProvider,
ObjectProvider observationRegistryProvider,
ObjectProvider observationConventionProvider,
MessagingMessageConverter messageConverter) {
@@ -114,7 +119,8 @@ public SqsMessageListenerContainerFactory
+
+ tools.jackson.core
+ jackson-databind
+ true
+
org.springframework.integration
spring-integration-file
diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java
index 02317595f0..c04671ac26 100644
--- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java
+++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java
@@ -15,12 +15,11 @@
*/
package io.awspring.cloud.s3;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
import java.io.InputStream;
import org.springframework.util.Assert;
import software.amazon.awssdk.core.sync.RequestBody;
+import tools.jackson.core.JacksonException;
+import tools.jackson.databind.json.JsonMapper;
/**
* Jackson based implementation of {@link S3ObjectConverter}. Serializes/deserializes objects to/from JSON.
@@ -29,20 +28,20 @@
* @since 3.0
*/
public class Jackson2JsonS3ObjectConverter implements S3ObjectConverter {
- private final ObjectMapper objectMapper;
+ private final JsonMapper jsonMapper;
- public Jackson2JsonS3ObjectConverter(ObjectMapper objectMapper) {
- Assert.notNull(objectMapper, "objectMapper is required");
- this.objectMapper = objectMapper;
+ public Jackson2JsonS3ObjectConverter(JsonMapper jsonMapper) {
+ Assert.notNull(jsonMapper, "jsonMapper is required");
+ this.jsonMapper = jsonMapper;
}
@Override
public RequestBody write(T object) {
Assert.notNull(object, "object is required");
try {
- return RequestBody.fromBytes(objectMapper.writeValueAsBytes(object));
+ return RequestBody.fromBytes(jsonMapper.writeValueAsBytes(object));
}
- catch (JsonProcessingException e) {
+ catch (JacksonException e) {
throw new S3Exception("Failed to serialize object to JSON", e);
}
}
@@ -52,9 +51,9 @@ public T read(InputStream is, Class clazz) {
Assert.notNull(is, "InputStream is required");
Assert.notNull(clazz, "Clazz is required");
try {
- return objectMapper.readValue(is, clazz);
+ return jsonMapper.readValue(is, clazz);
}
- catch (IOException e) {
+ catch (JacksonException e) {
throw new S3Exception("Failed to deserialize object from JSON", e);
}
}
diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java
new file mode 100644
index 0000000000..3afe3a39a8
--- /dev/null
+++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.s3;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.InputStream;
+import org.springframework.util.Assert;
+import software.amazon.awssdk.core.sync.RequestBody;
+
+/**
+ * Jackson 2 based implementation of {@link S3ObjectConverter}. Serializes/deserializes objects to/from JSON.
+ *
+ * @author Maciej Walkowiak
+ * @since 4.0
+ */
+@Deprecated
+public class LegacyJackson2JsonS3ObjectConverter implements S3ObjectConverter {
+ private final ObjectMapper objectMapper;
+
+ public LegacyJackson2JsonS3ObjectConverter(ObjectMapper objectMapper) {
+ Assert.notNull(objectMapper, "objectMapper is required");
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public RequestBody write(T object) {
+ Assert.notNull(object, "object is required");
+ try {
+ return RequestBody.fromBytes(objectMapper.writeValueAsBytes(object));
+ }
+ catch (JacksonException e) {
+ throw new S3Exception("Failed to serialize object to JSON", e);
+ }
+ }
+
+ @Override
+ public T read(InputStream is, Class clazz) {
+ Assert.notNull(is, "InputStream is required");
+ Assert.notNull(clazz, "Clazz is required");
+ try {
+ return objectMapper.readValue(is, clazz);
+ }
+ catch (IOException e) {
+ throw new S3Exception("Failed to deserialize object from JSON", e);
+ }
+ }
+
+ @Override
+ public String contentType() {
+ return "application/json";
+ }
+}
diff --git a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java
index f3b127b07e..6517a15efd 100644
--- a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java
+++ b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java
@@ -19,7 +19,6 @@
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatNoException;
-import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -53,6 +52,7 @@
import software.amazon.awssdk.services.s3.model.ListBucketsResponse;
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import tools.jackson.databind.json.JsonMapper;
/**
* Integration tests for {@link S3Template}.
@@ -85,7 +85,7 @@ static void beforeAll() {
void init() {
this.s3Template = new S3Template(client,
new DiskBufferingS3OutputStreamProvider(client, new PropertiesS3ObjectContentTypeResolver()),
- new Jackson2JsonS3ObjectConverter(new ObjectMapper()), presigner);
+ new Jackson2JsonS3ObjectConverter(new JsonMapper()), presigner);
client.createBucket(r -> r.bucket(BUCKET_NAME));
}
diff --git a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/Jackson2SecretValueReader.java b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/Jackson2SecretValueReader.java
new file mode 100644
index 0000000000..a9a448f0f4
--- /dev/null
+++ b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/Jackson2SecretValueReader.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.secretsmanager;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Map;
+
+@Deprecated
+public class Jackson2SecretValueReader implements SecretValueReader {
+ private final ObjectMapper objectMapper;
+
+ public Jackson2SecretValueReader() {
+ this.objectMapper = new ObjectMapper();
+ }
+
+ @Override
+ public Map readSecretValue(String secretString) {
+ try {
+ return objectMapper.readValue(secretString, new TypeReference<>() {
+ });
+ }
+ catch (JacksonException e) {
+ throw new SecretParseException(e);
+ }
+ }
+}
diff --git a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/JacksonSecretValueReader.java b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/JacksonSecretValueReader.java
new file mode 100644
index 0000000000..c6e996debc
--- /dev/null
+++ b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/JacksonSecretValueReader.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.secretsmanager;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import java.util.Map;
+
+public class JacksonSecretValueReader implements SecretValueReader {
+ private final JsonMapper jsonMapper;
+
+ public JacksonSecretValueReader() {
+ this.jsonMapper = new JsonMapper();
+ }
+
+ @Override
+ public Map readSecretValue(String secretString) {
+ try {
+ return jsonMapper.readValue(secretString, new TypeReference<>() {
+ });
+ }
+ catch (JacksonException e) {
+ throw new SecretParseException(e);
+ }
+ }
+}
diff --git a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretParseException.java b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretParseException.java
new file mode 100644
index 0000000000..4506663de4
--- /dev/null
+++ b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretParseException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.secretsmanager;
+
+/**
+ * @author Maciej Walkowiak
+ * @since 4.0.0
+ */
+class SecretParseException extends RuntimeException {
+ SecretParseException(Exception cause) {
+ super(cause);
+ }
+}
diff --git a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretValueReader.java b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretValueReader.java
new file mode 100644
index 0000000000..8d3590447a
--- /dev/null
+++ b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretValueReader.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.secretsmanager;
+
+import java.util.Map;
+
+public interface SecretValueReader {
+ Map readSecretValue(String secretString);
+}
diff --git a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretsManagerPropertySource.java b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretsManagerPropertySource.java
index 2c7f02059a..83b3f63bed 100644
--- a/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretsManagerPropertySource.java
+++ b/spring-cloud-aws-secrets-manager/src/main/java/io/awspring/cloud/secretsmanager/SecretsManagerPropertySource.java
@@ -15,11 +15,8 @@
*/
package io.awspring.cloud.secretsmanager;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.core.config.AwsPropertySource;
+import io.awspring.cloud.core.support.JacksonPresent;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@@ -48,7 +45,7 @@ public class SecretsManagerPropertySource
private static Log LOG = LogFactory.getLog(SecretsManagerPropertySource.class);
private static final String PREFIX_PART = "?prefix=";
- private final ObjectMapper jsonMapper = new ObjectMapper();
+ private final SecretValueReader secretValueReader;
/**
* Full secret path containing both secret id and prefix.
@@ -75,6 +72,16 @@ public SecretsManagerPropertySource(String context, SecretsManagerClient smClien
this.context = context;
this.secretId = resolveSecretId(context);
this.prefix = resolvePrefix(context);
+ if (JacksonPresent.isJackson3Present()) {
+ this.secretValueReader = new JacksonSecretValueReader();
+ }
+ else if (JacksonPresent.isJackson2Present()) {
+ this.secretValueReader = new Jackson2SecretValueReader();
+ }
+ else {
+ throw new IllegalStateException(
+ "SecretsManagerPropertySource requires a Jackson 2 or Jackson 3 library on the classpath");
+ }
}
/**
@@ -102,9 +109,7 @@ private void readSecretValue(GetSecretValueRequest secretValueRequest) {
GetSecretValueResponse secretValueResponse = source.getSecretValue(secretValueRequest);
if (secretValueResponse.secretString() != null) {
try {
- Map secretMap = jsonMapper.readValue(secretValueResponse.secretString(),
- new TypeReference<>() {
- });
+ Map secretMap = secretValueReader.readSecretValue(secretValueResponse.secretString());
for (Map.Entry secretEntry : secretMap.entrySet()) {
LOG.debug("Populating property retrieved from AWS Secrets Manager: " + secretEntry.getKey());
@@ -112,7 +117,7 @@ private void readSecretValue(GetSecretValueRequest secretValueRequest) {
properties.put(propertyKey, secretEntry.getValue());
}
}
- catch (JsonParseException e) {
+ catch (SecretParseException e) {
// If the secret is not a JSON string, then it is a simple "plain text" string
String[] parts = secretValueResponse.name().split("/");
String secretName = parts[parts.length - 1];
@@ -120,7 +125,7 @@ private void readSecretValue(GetSecretValueRequest secretValueRequest) {
String propertyKey = prefix != null ? prefix + secretName : secretName;
properties.put(propertyKey, secretValueResponse.secretString());
}
- catch (JsonProcessingException e) {
+ catch (Exception e) {
throw new RuntimeException(e);
}
}
diff --git a/spring-cloud-aws-sns/pom.xml b/spring-cloud-aws-sns/pom.xml
index 9759c527fb..e40154a620 100644
--- a/spring-cloud-aws-sns/pom.xml
+++ b/spring-cloud-aws-sns/pom.xml
@@ -80,6 +80,11 @@
sqs
test
+
+ tools.jackson.core
+ jackson-core
+ true
+
diff --git a/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/Jackson2JsonStringEncoder.java b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/Jackson2JsonStringEncoder.java
new file mode 100644
index 0000000000..4a986a7396
--- /dev/null
+++ b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/Jackson2JsonStringEncoder.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sns.core;
+
+import com.fasterxml.jackson.core.io.JsonStringEncoder;
+
+@Deprecated
+public class Jackson2JsonStringEncoder implements JsonStringEncoderDelegator {
+ private final JsonStringEncoder delegate = JsonStringEncoder.getInstance();
+
+ @Override
+ public void quoteAsString(CharSequence input, StringBuilder output) {
+ delegate.quoteAsString(input, output);
+ }
+}
diff --git a/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JacksonJsonStringEncoder.java b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JacksonJsonStringEncoder.java
new file mode 100644
index 0000000000..af6e6b7cf1
--- /dev/null
+++ b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JacksonJsonStringEncoder.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sns.core;
+
+import tools.jackson.core.io.JsonStringEncoder;
+
+public class JacksonJsonStringEncoder implements JsonStringEncoderDelegator {
+ private final JsonStringEncoder delegate = JsonStringEncoder.getInstance();
+
+ @Override
+ public void quoteAsString(CharSequence input, StringBuilder output) {
+ delegate.quoteAsString(input, output);
+ }
+}
diff --git a/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JsonStringEncoderDelegator.java b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JsonStringEncoderDelegator.java
new file mode 100644
index 0000000000..43ffdae90f
--- /dev/null
+++ b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JsonStringEncoderDelegator.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sns.core;
+
+import io.awspring.cloud.core.support.JacksonPresent;
+
+public interface JsonStringEncoderDelegator {
+ static JsonStringEncoderDelegator create() {
+ if (JacksonPresent.isJackson3Present()) {
+ return new JacksonJsonStringEncoder();
+ }
+ else if (JacksonPresent.isJackson2Present()) {
+ return new Jackson2JsonStringEncoder();
+ }
+ else {
+ throw new IllegalStateException(
+ "JsonStringEncoder requires a Jackson 2 or Jackson 3 library on the classpath");
+ }
+ }
+
+ void quoteAsString(CharSequence input, StringBuilder output);
+}
diff --git a/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/TopicMessageChannel.java b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/TopicMessageChannel.java
index 4e9eed44ab..6722e5a9fc 100644
--- a/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/TopicMessageChannel.java
+++ b/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/TopicMessageChannel.java
@@ -19,7 +19,6 @@
import static io.awspring.cloud.sns.core.SnsHeaders.MESSAGE_GROUP_ID_HEADER;
import static io.awspring.cloud.sns.core.SnsHeaders.NOTIFICATION_SUBJECT_HEADER;
-import com.fasterxml.jackson.core.io.JsonStringEncoder;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
@@ -50,7 +49,7 @@
*/
public class TopicMessageChannel extends AbstractMessageChannel {
- private static final JsonStringEncoder jsonStringEncoder = JsonStringEncoder.getInstance();
+ private static final JsonStringEncoderDelegator jsonStringEncoder = JsonStringEncoderDelegator.create();
private final SnsClient snsClient;
@@ -134,10 +133,11 @@ private boolean isSkipHeader(String headerName) {
}
private MessageAttributeValue getStringArrayMessageAttribute(List messageHeaderValue) {
-
- String stringValue = "[" + messageHeaderValue.stream()
- .map(item -> "\"" + String.valueOf(jsonStringEncoder.quoteAsString(item.toString())) + "\"")
- .collect(Collectors.joining(", ")) + "]";
+ String stringValue = messageHeaderValue.stream().map(item -> {
+ StringBuilder sb = new StringBuilder();
+ jsonStringEncoder.quoteAsString(item.toString(), sb);
+ return "\"" + sb + "\"";
+ }).collect(Collectors.joining(", ", "[", "]"));
return MessageAttributeValue.builder().dataType(MessageAttributeDataTypes.STRING_ARRAY).stringValue(stringValue)
.build();
diff --git a/spring-cloud-aws-sqs/pom.xml b/spring-cloud-aws-sqs/pom.xml
index 1236920d89..ab79a138af 100644
--- a/spring-cloud-aws-sqs/pom.xml
+++ b/spring-cloud-aws-sqs/pom.xml
@@ -42,6 +42,12 @@
com.fasterxml.jackson.core
jackson-databind
+ true
+
+
+ tools.jackson.core
+ jackson-databind
+ true
io.awspring.cloud
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/AbstractListenerAnnotationBeanPostProcessor.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/AbstractListenerAnnotationBeanPostProcessor.java
index 506d3e5c60..0b55695cb9 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/AbstractListenerAnnotationBeanPostProcessor.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/AbstractListenerAnnotationBeanPostProcessor.java
@@ -15,14 +15,11 @@
*/
package io.awspring.cloud.sqs.annotation;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.ConfigUtils;
-import io.awspring.cloud.sqs.config.Endpoint;
-import io.awspring.cloud.sqs.config.EndpointRegistrar;
-import io.awspring.cloud.sqs.config.HandlerMethodEndpoint;
-import io.awspring.cloud.sqs.config.SqsEndpoint;
-import io.awspring.cloud.sqs.config.SqsListenerConfigurer;
+import io.awspring.cloud.sqs.config.*;
import io.awspring.cloud.sqs.listener.acknowledgement.handler.AcknowledgementMode;
+import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.JacksonJsonMessageConverterFactory;
import io.awspring.cloud.sqs.support.resolver.AcknowledgmentHandlerMethodArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.BatchAcknowledgmentArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.BatchPayloadMethodArgumentResolver;
@@ -56,7 +53,6 @@
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.lang.Nullable;
import org.springframework.messaging.converter.CompositeMessageConverter;
-import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SimpleMessageConverter;
import org.springframework.messaging.converter.StringMessageConverter;
@@ -70,6 +66,7 @@
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
+import tools.jackson.databind.json.JsonMapper;
/**
* {@link BeanPostProcessor} implementation that scans beans for a {@link SqsListener @SqsListener} annotation, extracts
@@ -109,6 +106,10 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw
return bean;
}
+ protected EndpointRegistrar createEndpointRegistrar() {
+ return new EndpointRegistrar();
+ }
+
@Nullable
protected ConfigurableBeanFactory getConfigurableBeanFactory() {
return this.beanFactory instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) this.beanFactory : null;
@@ -314,8 +315,8 @@ protected void initializeHandlerMethodFactory() {
protected void configureDefaultHandlerMethodFactory(DefaultMessageHandlerMethodFactory handlerMethodFactory) {
CompositeMessageConverter compositeMessageConverter = createCompositeMessageConverter();
- List methodArgumentResolvers = new ArrayList<>(
- createAdditionalArgumentResolvers(compositeMessageConverter, this.endpointRegistrar.getObjectMapper()));
+ List methodArgumentResolvers = new ArrayList<>(createAdditionalArgumentResolvers(
+ compositeMessageConverter, new JacksonJsonMessageConverterFactory(new JsonMapper())));
methodArgumentResolvers.addAll(createArgumentResolvers(compositeMessageConverter));
this.endpointRegistrar.getMethodArgumentResolversConsumer().accept(methodArgumentResolvers);
handlerMethodFactory.setArgumentResolvers(methodArgumentResolvers);
@@ -323,7 +324,12 @@ protected void configureDefaultHandlerMethodFactory(DefaultMessageHandlerMethodF
}
protected Collection createAdditionalArgumentResolvers(
- MessageConverter messageConverter, ObjectMapper objectMapper) {
+ MessageConverter messageConverter, AbstractMessageConverterFactory wrapper) {
+ return createAdditionalArgumentResolvers();
+ }
+
+ protected Collection createAdditionalArgumentResolvers(
+ MessageConverter messageConverter) {
return createAdditionalArgumentResolvers();
}
@@ -335,7 +341,9 @@ protected CompositeMessageConverter createCompositeMessageConverter() {
List messageConverters = new ArrayList<>();
messageConverters.add(new StringMessageConverter());
messageConverters.add(new SimpleMessageConverter());
- messageConverters.add(createDefaultMappingJackson2MessageConverter(this.endpointRegistrar.getObjectMapper()));
+ if (endpointRegistrar.getAbstractMessageConverterFactory() != null) {
+ messageConverters.add(endpointRegistrar.getAbstractMessageConverterFactory().create());
+ }
this.endpointRegistrar.getMessageConverterConsumer().accept(messageConverters);
return new CompositeMessageConverter(messageConverters);
}
@@ -353,20 +361,6 @@ protected List createArgumentResolvers(MessageCon
}
// @formatter:on
- protected MappingJackson2MessageConverter createDefaultMappingJackson2MessageConverter(ObjectMapper objectMapper) {
- MappingJackson2MessageConverter jacksonMessageConverter = new MappingJackson2MessageConverter();
- jacksonMessageConverter.setSerializedPayloadClass(String.class);
- jacksonMessageConverter.setStrictContentTypeMatch(false);
- if (objectMapper != null) {
- jacksonMessageConverter.setObjectMapper(objectMapper);
- }
- return jacksonMessageConverter;
- }
-
- protected EndpointRegistrar createEndpointRegistrar() {
- return new EndpointRegistrar();
- }
-
private static class DelegatingMessageHandlerMethodFactory implements MessageHandlerMethodFactory {
private MessageHandlerMethodFactory delegate;
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessor.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessor.java
index 02ee705138..6032c08fdf 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessor.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessor.java
@@ -15,12 +15,15 @@
*/
package io.awspring.cloud.sqs.annotation;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.config.Endpoint;
import io.awspring.cloud.sqs.config.MultiMethodSqsEndpoint;
import io.awspring.cloud.sqs.config.SqsBeanNames;
import io.awspring.cloud.sqs.config.SqsEndpoint;
import io.awspring.cloud.sqs.listener.SqsHeaders;
+import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.JacksonJsonMessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2NotificationSubjectArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.BatchVisibilityHandlerMethodArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.NotificationMessageArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.NotificationSubjectArgumentResolver;
@@ -28,6 +31,8 @@
import io.awspring.cloud.sqs.support.resolver.SnsNotificationArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.SqsMessageMethodArgumentResolver;
import io.awspring.cloud.sqs.support.resolver.VisibilityHandlerMethodArgumentResolver;
+import io.awspring.cloud.sqs.support.resolver.jacskon2.LegacyJackson2NotificationMessageArgumentResolver;
+import io.awspring.cloud.sqs.support.resolver.jacskon2.LegacyJackson2SnsNotificationArgumentResolver;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -106,12 +111,23 @@ protected Collection createAdditionalArgumentReso
@Override
protected Collection createAdditionalArgumentResolvers(
- MessageConverter messageConverter, ObjectMapper objectMapper) {
+ MessageConverter messageConverter, AbstractMessageConverterFactory wrapper) {
List argumentResolvers = new ArrayList<>(createAdditionalArgumentResolvers());
- if (objectMapper != null) {
- argumentResolvers.add(new NotificationMessageArgumentResolver(messageConverter, objectMapper));
- argumentResolvers.add(new NotificationSubjectArgumentResolver(objectMapper));
- argumentResolvers.add(new SnsNotificationArgumentResolver(messageConverter, objectMapper));
+ if (wrapper instanceof JacksonJsonMessageConverterFactory) {
+ argumentResolvers.add(new NotificationMessageArgumentResolver(messageConverter,
+ ((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
+ argumentResolvers.add(new NotificationSubjectArgumentResolver(
+ ((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
+ argumentResolvers.add(new SnsNotificationArgumentResolver(messageConverter,
+ ((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
+ }
+ else if (wrapper instanceof LegacyJackson2MessageConverterFactory) {
+ argumentResolvers.add(new LegacyJackson2NotificationMessageArgumentResolver(messageConverter,
+ ((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
+ argumentResolvers.add(new LegacyJackson2NotificationSubjectArgumentResolver(
+ ((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
+ argumentResolvers.add(new LegacyJackson2SnsNotificationArgumentResolver(messageConverter,
+ ((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
}
return argumentResolvers;
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/EndpointRegistrar.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/EndpointRegistrar.java
index 48e90df52b..9e33be3a87 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/EndpointRegistrar.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/EndpointRegistrar.java
@@ -15,9 +15,9 @@
*/
package io.awspring.cloud.sqs.config;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.listener.MessageListenerContainer;
import io.awspring.cloud.sqs.listener.MessageListenerContainerRegistry;
+import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -73,7 +73,7 @@ public class EndpointRegistrar implements BeanFactoryAware, SmartInitializingSin
};
@Nullable
- private ObjectMapper objectMapper;
+ private AbstractMessageConverterFactory abstractMessageConverterFactory;
@Nullable
private Validator validator;
@@ -118,11 +118,11 @@ public void setMessageListenerContainerRegistryBeanName(String messageListenerCo
/**
* Set the object mapper to be used to deserialize payloads fot SqsListener endpoints.
- * @param objectMapper the object mapper instance.
+ * @param abstractMessageConverterFactory the jacksonMapperWrapper instance.
*/
- public void setObjectMapper(ObjectMapper objectMapper) {
- Assert.notNull(objectMapper, "objectMapper cannot be null.");
- this.objectMapper = objectMapper;
+ public void setJacksonMapperWrapper(AbstractMessageConverterFactory abstractMessageConverterFactory) {
+ Assert.notNull(abstractMessageConverterFactory, "jacksonMapperWrapper cannot be null.");
+ this.abstractMessageConverterFactory = abstractMessageConverterFactory;
}
/**
@@ -173,8 +173,8 @@ public Consumer> getMethodArgumentResolversC
* @return the object mapper instance.
*/
@Nullable
- public ObjectMapper getObjectMapper() {
- return this.objectMapper;
+ public AbstractMessageConverterFactory getAbstractMessageConverterFactory() {
+ return this.abstractMessageConverterFactory;
}
/**
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/JacksonAbstractMessageConverterFactory.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/JacksonAbstractMessageConverterFactory.java
new file mode 100644
index 0000000000..5e4b55c0c0
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/config/JacksonAbstractMessageConverterFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.jspecify.annotations.Nullable;
+import org.springframework.messaging.converter.JacksonJsonMessageConverter;
+import org.springframework.messaging.converter.MappingJackson2MessageConverter;
+import tools.jackson.databind.json.JsonMapper;
+
+public class JacksonAbstractMessageConverterFactory {
+ @Deprecated
+ public static MappingJackson2MessageConverter createLegacyJackson2MessageConverter(
+ @Nullable ObjectMapper objectMapper) {
+ MappingJackson2MessageConverter jacksonMessageConverter = new MappingJackson2MessageConverter();
+ jacksonMessageConverter.setSerializedPayloadClass(String.class);
+ jacksonMessageConverter.setStrictContentTypeMatch(false);
+ if (objectMapper != null) {
+ jacksonMessageConverter.setObjectMapper(objectMapper);
+ }
+ return jacksonMessageConverter;
+ }
+
+ public static JacksonJsonMessageConverter createJacksonJsonMessageConverter(JsonMapper jsonMapper) {
+ JacksonJsonMessageConverter jacksonMessageConverter;
+ if (jsonMapper != null) {
+ jacksonMessageConverter = new JacksonJsonMessageConverter(jsonMapper);
+ }
+ else {
+ jacksonMessageConverter = new JacksonJsonMessageConverter();
+ }
+ jacksonMessageConverter.setSerializedPayloadClass(String.class);
+ jacksonMessageConverter.setStrictContentTypeMatch(false);
+ return jacksonMessageConverter;
+ }
+
+ public static JacksonJsonMessageConverter createDefaultMappingJacksonMessageConverter() {
+ JacksonJsonMessageConverter messageConverter = new JacksonJsonMessageConverter();
+ messageConverter.setSerializedPayloadClass(String.class);
+ messageConverter.setStrictContentTypeMatch(false);
+ return messageConverter;
+ }
+
+ @Deprecated
+ public static MappingJackson2MessageConverter createDefaultMappingLegacyJackson2MessageConverter() {
+ MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
+ messageConverter.setSerializedPayloadClass(String.class);
+ messageConverter.setStrictContentTypeMatch(false);
+ return messageConverter;
+ }
+
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/AbstractContainerOptions.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/AbstractContainerOptions.java
index 85874aae67..294d3286cf 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/AbstractContainerOptions.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/listener/AbstractContainerOptions.java
@@ -21,6 +21,7 @@
import io.awspring.cloud.sqs.listener.backpressure.BackPressureHandlerFactory;
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import io.micrometer.observation.ObservationConvention;
import io.micrometer.observation.ObservationRegistry;
import java.time.Duration;
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplate.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplate.java
index a34ad857db..1b23b40c65 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplate.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplate.java
@@ -28,7 +28,7 @@
import io.awspring.cloud.sqs.support.converter.MessageConversionContext;
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
import io.awspring.cloud.sqs.support.converter.SqsMessageConversionContext;
-import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import io.awspring.cloud.sqs.support.observation.SqsTemplateObservation;
import java.time.Duration;
import java.util.Collection;
@@ -645,8 +645,8 @@ private V getValueAs(Map headers, String headerName, Class
@@ -741,10 +741,10 @@ public SqsTemplateBuilder messageConverter(MessagingMessageConverter me
@Override
public SqsTemplateBuilder configureDefaultConverter(
- Consumer messageConverterConfigurer) {
+ Consumer messageConverterConfigurer) {
Assert.notNull(messageConverterConfigurer, "messageConverterConfigurer must not be null");
Assert.isNull(this.messageConverter, "messageConverter already configured");
- SqsMessagingMessageConverter defaultMessageConverter = createDefaultMessageConverter();
+ LegacySqsMessagingMessageConverter defaultMessageConverter = createDefaultMessageConverter();
messageConverterConfigurer.accept(defaultMessageConverter);
this.messageConverter = defaultMessageConverter;
return this;
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplateBuilder.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplateBuilder.java
index 0c2e924d66..7cea5ff3b6 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplateBuilder.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/operations/SqsTemplateBuilder.java
@@ -16,7 +16,7 @@
package io.awspring.cloud.sqs.operations;
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
-import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import java.util.function.Consumer;
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
import software.amazon.awssdk.services.sqs.model.Message;
@@ -46,10 +46,11 @@ public interface SqsTemplateBuilder {
/**
* Configure the default message converter.
*
- * @param messageConverterConfigurer a {@link SqsMessagingMessageConverter} consumer.
+ * @param messageConverterConfigurer a {@link LegacySqsMessagingMessageConverter} consumer.
* @return the builder.
*/
- SqsTemplateBuilder configureDefaultConverter(Consumer messageConverterConfigurer);
+ SqsTemplateBuilder configureDefaultConverter(
+ Consumer messageConverterConfigurer);
/**
* Configure options for the template.
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessageConverterFactory.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessageConverterFactory.java
new file mode 100644
index 0000000000..1eb2fcc4bd
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessageConverterFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter;
+
+import org.springframework.messaging.converter.MessageConverter;
+
+public abstract class AbstractMessageConverterFactory {
+ public abstract MessageConverter create();
+
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessagingMessageConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessagingMessageConverter.java
index a3f854fb6d..6dfb80e130 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessagingMessageConverter.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractMessagingMessageConverter.java
@@ -15,23 +15,16 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.MessageHeaderUtils;
import io.awspring.cloud.sqs.listener.SqsHeaders;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
-import java.util.Optional;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
-import org.springframework.messaging.converter.CompositeMessageConverter;
-import org.springframework.messaging.converter.MappingJackson2MessageConverter;
-import org.springframework.messaging.converter.MessageConverter;
-import org.springframework.messaging.converter.StringMessageConverter;
+import org.springframework.messaging.converter.*;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.Assert;
@@ -51,7 +44,7 @@ public abstract class AbstractMessagingMessageConverter implements ContextAwa
private String typeHeader = SqsHeaders.SQS_DEFAULT_TYPE_HEADER;
- private MessageConverter payloadMessageConverter;
+ public MessageConverter payloadMessageConverter;
private HeaderMapper headerMapper;
@@ -61,7 +54,6 @@ public abstract class AbstractMessagingMessageConverter implements ContextAwa
.getName();
protected AbstractMessagingMessageConverter() {
- this.payloadMessageConverter = createDefaultCompositeMessageConverter();
this.headerMapper = createDefaultHeaderMapper();
this.payloadTypeMapper = this::defaultHeaderTypeMapping;
}
@@ -87,29 +79,6 @@ public void setPayloadMessageConverter(MessageConverter messageConverter) {
this.payloadMessageConverter = messageConverter;
}
- /**
- * Set the {@link ObjectMapper} instance to be used for converting the {@link Message} instances payloads.
- * @param objectMapper the object mapper instance.
- */
- public void setObjectMapper(ObjectMapper objectMapper) {
- Assert.notNull(objectMapper, "messageConverter cannot be null");
- MappingJackson2MessageConverter converter = getMappingJackson2MessageConverter().orElseThrow(
- () -> new IllegalStateException("%s can only be set in %s instances, or %s containing one.".formatted(
- ObjectMapper.class.getSimpleName(), MappingJackson2MessageConverter.class.getSimpleName(),
- CompositeMessageConverter.class.getSimpleName())));
- converter.setObjectMapper(objectMapper);
- }
-
- private Optional getMappingJackson2MessageConverter() {
- return this.payloadMessageConverter instanceof CompositeMessageConverter compositeConverter
- ? compositeConverter.getConverters().stream()
- .filter(converter -> converter instanceof MappingJackson2MessageConverter)
- .map(MappingJackson2MessageConverter.class::cast).findFirst()
- : this.payloadMessageConverter instanceof MappingJackson2MessageConverter converter
- ? Optional.of(converter)
- : Optional.empty();
- }
-
/**
* Get the {@link MessageConverter} to be used for converting the {@link Message} instances payloads.
* @return the instance.
@@ -237,31 +206,16 @@ private MessageHeaders getMessageHeaders(Message> message) {
protected abstract S doConvertMessage(S messageWithHeaders, Object payload);
- private CompositeMessageConverter createDefaultCompositeMessageConverter() {
- List messageConverters = new ArrayList<>();
- messageConverters.add(createClassMatchingMessageConverter());
- messageConverters.add(createStringMessageConverter());
- messageConverters.add(createDefaultMappingJackson2MessageConverter());
- return new CompositeMessageConverter(messageConverters);
- }
-
- private SimpleClassMatchingMessageConverter createClassMatchingMessageConverter() {
+ public SimpleClassMatchingMessageConverter createClassMatchingMessageConverter() {
SimpleClassMatchingMessageConverter matchingMessageConverter = new SimpleClassMatchingMessageConverter();
matchingMessageConverter.setSerializedPayloadClass(String.class);
return matchingMessageConverter;
}
- private StringMessageConverter createStringMessageConverter() {
+ public StringMessageConverter createStringMessageConverter() {
StringMessageConverter stringMessageConverter = new StringMessageConverter();
stringMessageConverter.setSerializedPayloadClass(String.class);
return stringMessageConverter;
}
- private MappingJackson2MessageConverter createDefaultMappingJackson2MessageConverter() {
- MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
- messageConverter.setSerializedPayloadClass(String.class);
- messageConverter.setStrictContentTypeMatch(false);
- return messageConverter;
- }
-
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractSnsJsonNode.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractSnsJsonNode.java
new file mode 100644
index 0000000000..90229a2241
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/AbstractSnsJsonNode.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter;
+
+public abstract class AbstractSnsJsonNode {
+
+ public abstract String getMessageAsString();
+
+ public abstract String getSubjectAsString();
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/JacksonJsonMessageConverterFactory.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/JacksonJsonMessageConverterFactory.java
new file mode 100644
index 0000000000..74a35b5904
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/JacksonJsonMessageConverterFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter;
+
+import io.awspring.cloud.sqs.config.JacksonAbstractMessageConverterFactory;
+import org.springframework.messaging.converter.MessageConverter;
+import tools.jackson.databind.json.JsonMapper;
+
+public class JacksonJsonMessageConverterFactory extends AbstractMessageConverterFactory {
+ private JsonMapper jsonMapper;
+
+ public JacksonJsonMessageConverterFactory(JsonMapper jsonMapper) {
+ this.jsonMapper = jsonMapper;
+ }
+
+ public JsonMapper getJsonMapper() {
+ return jsonMapper;
+ }
+
+ public void setJsonMapper(JsonMapper jsonMapper) {
+ this.jsonMapper = jsonMapper;
+ }
+
+ public JacksonJsonMessageConverterFactory getJsonMapperWrapper() {
+ return this;
+ }
+
+ @Override
+ public MessageConverter create() {
+ return JacksonAbstractMessageConverterFactory.createJacksonJsonMessageConverter(jsonMapper);
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsJsonNode.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsJsonNode.java
index 145338df63..e7e7be7f86 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsJsonNode.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsJsonNode.java
@@ -15,20 +15,20 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.messaging.converter.MessageConversionException;
+import tools.jackson.databind.JsonNode;
+import tools.jackson.databind.json.JsonMapper;
/**
* @author Michael Sosa
* @author Alexander Nebel
* @since 3.3.1
*/
-public class SnsJsonNode {
+public class SnsJsonNode extends AbstractSnsJsonNode {
private final String jsonString;
private final JsonNode jsonNode;
- public SnsJsonNode(ObjectMapper jsonMapper, String jsonString) {
+ public SnsJsonNode(JsonMapper jsonMapper, String jsonString) {
try {
this.jsonString = jsonString;
jsonNode = jsonMapper.readTree(jsonString);
@@ -45,7 +45,7 @@ void validate() throws MessageConversionException {
null);
}
- if (!"Notification".equals(jsonNode.get("Type").asText())) {
+ if (!"Notification".equals(jsonNode.get("Type").asString())) {
throw new MessageConversionException("Payload: '" + jsonString + "' is not a valid notification", null);
}
@@ -54,10 +54,12 @@ void validate() throws MessageConversionException {
}
}
+ @Override
public String getMessageAsString() {
- return jsonNode.get("Message").asText();
+ return jsonNode.get("Message").asString();
}
+ @Override
public String getSubjectAsString() {
if (!jsonNode.has("Subject")) {
throw new MessageConversionException("Payload: '" + jsonString + "' does not contain a subject", null);
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsMessageConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsMessageConverter.java
index 6e1a42071b..9797033738 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsMessageConverter.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsMessageConverter.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
@@ -29,6 +28,7 @@
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.Assert;
+import tools.jackson.databind.json.JsonMapper;
/**
* @author Michael Sosa
@@ -38,11 +38,11 @@
*/
public class SnsMessageConverter implements SmartMessageConverter {
- private final ObjectMapper jsonMapper;
+ private final JsonMapper jsonMapper;
private final MessageConverter payloadConverter;
- public SnsMessageConverter(MessageConverter payloadConverter, ObjectMapper jsonMapper) {
+ public SnsMessageConverter(MessageConverter payloadConverter, JsonMapper jsonMapper) {
Assert.notNull(payloadConverter, "payloadConverter must not be null");
Assert.notNull(jsonMapper, "jsonMapper must not be null");
this.payloadConverter = payloadConverter;
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverter.java
index ad970c09ca..26c91bd303 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverter.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverter.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
@@ -29,6 +28,7 @@
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.Assert;
+import tools.jackson.databind.json.JsonMapper;
/**
* Converter that extracts SNS notifications from SQS messages and creates {@link SnsNotification} objects.
@@ -38,7 +38,7 @@
*/
public class SnsNotificationConverter implements SmartMessageConverter {
- private final ObjectMapper jsonMapper;
+ private final JsonMapper jsonMapper;
private final MessageConverter payloadConverter;
@@ -47,7 +47,7 @@ public class SnsNotificationConverter implements SmartMessageConverter {
* @param payloadConverter the converter to use for the message payload
* @param jsonMapper the JSON mapper to use for parsing the SNS notification
*/
- public SnsNotificationConverter(MessageConverter payloadConverter, ObjectMapper jsonMapper) {
+ public SnsNotificationConverter(MessageConverter payloadConverter, JsonMapper jsonMapper) {
Assert.notNull(payloadConverter, "payloadConverter must not be null");
Assert.notNull(jsonMapper, "jsonMapper must not be null");
this.payloadConverter = payloadConverter;
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsSubjectConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsSubjectConverter.java
index f371e411f9..8416964426 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsSubjectConverter.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SnsSubjectConverter.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -23,6 +22,7 @@
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
+import tools.jackson.databind.json.JsonMapper;
/**
* @author Alexander Nebel
@@ -30,11 +30,11 @@
*/
public class SnsSubjectConverter implements MessageConverter {
- private final ObjectMapper objectMapper;
+ private final JsonMapper jsonMapper;
- public SnsSubjectConverter(ObjectMapper objectMapper) {
- Assert.notNull(objectMapper, "jsonMapper must not be null");
- this.objectMapper = objectMapper;
+ public SnsSubjectConverter(JsonMapper jsonMapper) {
+ Assert.notNull(jsonMapper, "jsonMapper must not be null");
+ this.jsonMapper = jsonMapper;
}
@Override
@@ -51,7 +51,7 @@ public Object fromMessage(Message> message, Class> targetClass) {
throw new MessageConversionException("Conversion of List is not supported", null);
}
- var snsJsonNode = new SnsJsonNode(objectMapper, message.getPayload().toString());
+ var snsJsonNode = new SnsJsonNode(jsonMapper, message.getPayload().toString());
return snsJsonNode.getSubjectAsString();
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsHeaderMapper.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsHeaderMapper.java
index 767f6bc1c2..98c737cebf 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsHeaderMapper.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsHeaderMapper.java
@@ -20,6 +20,7 @@
import io.awspring.cloud.sqs.listener.QueueAttributes;
import io.awspring.cloud.sqs.listener.QueueMessageVisibility;
import io.awspring.cloud.sqs.listener.SqsHeaders;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.util.HashMap;
@@ -52,7 +53,7 @@
* @author Maciej Walkowiak
*
* @since 3.0
- * @see SqsMessagingMessageConverter
+ * @see LegacySqsMessagingMessageConverter
*/
public class SqsHeaderMapper implements ContextAwareHeaderMapper {
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessageConversionContext.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessageConversionContext.java
index 2c50cc321e..9beaa32c0c 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessageConversionContext.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessageConversionContext.java
@@ -19,6 +19,7 @@
import io.awspring.cloud.sqs.listener.QueueAttributesAware;
import io.awspring.cloud.sqs.listener.SqsAsyncClientAware;
import io.awspring.cloud.sqs.listener.acknowledgement.AcknowledgementCallback;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHeaders;
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
@@ -30,7 +31,7 @@
* @author Tomaz Fernandes
* @since 3.0
* @see SqsHeaderMapper
- * @see SqsMessagingMessageConverter
+ * @see LegacySqsMessagingMessageConverter
*/
public class SqsMessageConversionContext
implements AcknowledgementAwareMessageConversionContext, SqsAsyncClientAware, QueueAttributesAware {
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverter.java
index 67d0879c93..654c4cd5f3 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverter.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,22 +15,29 @@
*/
package io.awspring.cloud.sqs.support.converter;
-import org.springframework.messaging.Message;
+import static io.awspring.cloud.sqs.config.JacksonAbstractMessageConverterFactory.createDefaultMappingJacksonMessageConverter;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.messaging.converter.CompositeMessageConverter;
+import org.springframework.messaging.converter.MessageConverter;
import org.springframework.util.Assert;
-/**
- * {@link MessagingMessageConverter} implementation for converting SQS
- * {@link software.amazon.awssdk.services.sqs.model.Message} instances to Spring Messaging {@link Message} instances.
- *
- * @author Tomaz Fernandes
- * @author Dongha kim
- * @since 3.0
- * @see SqsHeaderMapper
- * @see SqsMessageConversionContext
- */
public class SqsMessagingMessageConverter
extends AbstractMessagingMessageConverter {
+ public SqsMessagingMessageConverter() {
+ this.payloadMessageConverter = createDefaultCompositeMessageConverter();
+ }
+
+ private CompositeMessageConverter createDefaultCompositeMessageConverter() {
+ List messageConverters = new ArrayList<>();
+ messageConverters.add(createClassMatchingMessageConverter());
+ messageConverters.add(createStringMessageConverter());
+ messageConverters.add(createDefaultMappingJacksonMessageConverter());
+ return new CompositeMessageConverter(messageConverters);
+ }
+
@Override
protected HeaderMapper createDefaultHeaderMapper() {
return new SqsHeaderMapper();
@@ -52,5 +59,4 @@ protected software.amazon.awssdk.services.sqs.model.Message doConvertMessage(
Assert.isInstanceOf(String.class, payload, "payload must be instance of String");
return messageWithHeaders.toBuilder().body((String) payload).build();
}
-
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2MessageConverterFactory.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2MessageConverterFactory.java
new file mode 100644
index 0000000000..f1a5149eda
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2MessageConverterFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.config.JacksonAbstractMessageConverterFactory;
+import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
+import org.springframework.messaging.converter.MessageConverter;
+
+@Deprecated
+public class LegacyJackson2MessageConverterFactory extends AbstractMessageConverterFactory {
+
+ private ObjectMapper objectMapper;
+
+ public LegacyJackson2MessageConverterFactory(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ public ObjectMapper getObjectMapper() {
+ return objectMapper;
+ }
+
+ public void setObjectMapper(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public MessageConverter create() {
+ return JacksonAbstractMessageConverterFactory.createLegacyJackson2MessageConverter(objectMapper);
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2NotificationSubjectArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2NotificationSubjectArgumentResolver.java
new file mode 100644
index 0000000000..c801b01dd0
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2NotificationSubjectArgumentResolver.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.annotation.SnsNotificationSubject;
+import java.lang.reflect.Executable;
+import java.util.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.MethodParameter;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
+import org.springframework.util.ClassUtils;
+
+/**
+ * @author Alexander Nebel
+ * @since 3.3.1
+ */
+@Deprecated
+public class LegacyJackson2NotificationSubjectArgumentResolver implements HandlerMethodArgumentResolver {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(LegacyJackson2NotificationSubjectArgumentResolver.class);
+
+ private final MessageConverter converter;
+
+ public LegacyJackson2NotificationSubjectArgumentResolver(ObjectMapper jsonMapper) {
+ this.converter = new LegacyJackson2SnsSubjectConverter(jsonMapper);
+ }
+
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ if (parameter.hasParameterAnnotation(SnsNotificationSubject.class)) {
+ if (ClassUtils.isAssignable(parameter.getParameterType(), String.class)) {
+ return true;
+ }
+ if (logger.isWarnEnabled()) {
+ logger.warn(
+ "Notification subject can only be injected into String assignable Types - No injection happening for {}#{}",
+ parameter.getDeclaringClass().getName(), getMethodName(parameter));
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Object resolveArgument(MethodParameter par, Message> msg) {
+ return converter.fromMessage(msg, par.getParameterType());
+ }
+
+ private String getMethodName(MethodParameter parameter) {
+ var method = parameter.getMethod();
+ var constructor = parameter.getConstructor();
+ return Optional.ofNullable(method != null ? method : constructor).map(Executable::getName)
+ .orElse("");
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsJsonNode.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsJsonNode.java
new file mode 100644
index 0000000000..33a62cc2ff
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsJsonNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.support.converter.AbstractSnsJsonNode;
+import org.springframework.messaging.converter.MessageConversionException;
+
+/**
+ * @author Michael Sosa
+ * @author Alexander Nebel
+ * @since 3.3.1
+ */
+@Deprecated
+public class LegacyJackson2SnsJsonNode extends AbstractSnsJsonNode {
+ private final String jsonString;
+ private final JsonNode jsonNode;
+
+ public LegacyJackson2SnsJsonNode(ObjectMapper jsonMapper, String jsonString) {
+ try {
+ this.jsonString = jsonString;
+ jsonNode = jsonMapper.readTree(jsonString);
+ }
+ catch (Exception e) {
+ throw new MessageConversionException("Could not read JSON", e);
+ }
+ validate();
+ }
+
+ void validate() throws MessageConversionException {
+ if (!jsonNode.has("Type")) {
+ throw new MessageConversionException("Payload: '" + jsonString + "' does not contain a Type attribute",
+ null);
+ }
+
+ if (!"Notification".equals(jsonNode.get("Type").asText())) {
+ throw new MessageConversionException("Payload: '" + jsonString + "' is not a valid notification", null);
+ }
+
+ if (!jsonNode.has("Message")) {
+ throw new MessageConversionException("Payload: '" + jsonString + "' does not contain a message", null);
+ }
+ }
+
+ @Override
+ public String getMessageAsString() {
+ return jsonNode.get("Message").asText();
+ }
+
+ @Override
+ public String getSubjectAsString() {
+ if (!jsonNode.has("Subject")) {
+ throw new MessageConversionException("Payload: '" + jsonString + "' does not contain a subject", null);
+ }
+ return jsonNode.get("Subject").asText();
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsMessageConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsMessageConverter.java
new file mode 100644
index 0000000000..ad1476af33
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsMessageConverter.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+import org.springframework.core.GenericTypeResolver;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ResolvableType;
+import org.springframework.lang.Nullable;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.converter.SmartMessageConverter;
+import org.springframework.messaging.support.GenericMessage;
+import org.springframework.util.Assert;
+
+@Deprecated
+public class LegacyJackson2SnsMessageConverter implements SmartMessageConverter {
+
+ private final ObjectMapper jsonMapper;
+
+ private final MessageConverter payloadConverter;
+
+ public LegacyJackson2SnsMessageConverter(MessageConverter payloadConverter, ObjectMapper jsonMapper) {
+ Assert.notNull(payloadConverter, "payloadConverter must not be null");
+ Assert.notNull(jsonMapper, "jsonMapper must not be null");
+ this.payloadConverter = payloadConverter;
+ this.jsonMapper = jsonMapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object fromMessage(Message> message, Class> targetClass, @Nullable Object conversionHint) {
+ Assert.notNull(message, "message must not be null");
+ Assert.notNull(targetClass, "target class must not be null");
+
+ Object payload = message.getPayload();
+
+ if (payload instanceof List messages) {
+ return fromGenericMessages(messages, targetClass, conversionHint);
+ }
+ else {
+ return fromGenericMessage((GenericMessage>) message, targetClass, conversionHint);
+ }
+ }
+
+ private Object fromGenericMessages(List> messages, Class> targetClass,
+ @Nullable Object conversionHint) {
+ Type resolvedType = getResolvedType(targetClass, conversionHint);
+ Class> resolvedClazz = ResolvableType.forType(resolvedType).resolve();
+
+ Object hint = targetClass.isAssignableFrom(List.class) && conversionHint instanceof MethodParameter mp
+ ? mp.nested()
+ : conversionHint;
+
+ return messages.stream().map(message -> fromGenericMessage(message, resolvedClazz, hint)).toList();
+ }
+
+ private Object fromGenericMessage(GenericMessage> message, Class> targetClass,
+ @Nullable Object conversionHint) {
+ var snsJsonNode = new LegacyJackson2SnsJsonNode(jsonMapper, message.getPayload().toString());
+
+ String messagePayload = snsJsonNode.getMessageAsString();
+ GenericMessage genericMessage = new GenericMessage<>(messagePayload);
+ return payloadConverter instanceof SmartMessageConverter smartMessageConverter
+ ? smartMessageConverter.fromMessage(genericMessage, targetClass, conversionHint)
+ : payloadConverter.fromMessage(genericMessage, targetClass);
+ }
+
+ @Override
+ public Object fromMessage(Message> message, Class> targetClass) {
+ return fromMessage(message, targetClass, null);
+ }
+
+ @Override
+ public Message> toMessage(Object payload, MessageHeaders headers) {
+ throw new UnsupportedOperationException(
+ "This converter only supports reading a SNS notification and not writing them");
+ }
+
+ @Override
+ public Message> toMessage(Object payload, MessageHeaders headers, Object conversionHint) {
+ throw new UnsupportedOperationException(
+ "This converter only supports reading a SNS notification and not writing them");
+ }
+
+ private static Type getResolvedType(Class> targetClass, @Nullable Object conversionHint) {
+ if (conversionHint instanceof MethodParameter param) {
+ param = param.nestedIfOptional();
+ if (Message.class.isAssignableFrom(param.getParameterType())) {
+ param = param.nested();
+ }
+ Type genericParameterType = param.getNestedGenericParameterType();
+ Class> contextClass = param.getContainingClass();
+ Type resolveType = GenericTypeResolver.resolveType(genericParameterType, contextClass);
+ if (resolveType instanceof ParameterizedType parameterizedType) {
+ return parameterizedType.getActualTypeArguments()[0];
+ }
+ else {
+ return resolveType;
+ }
+ }
+ return targetClass;
+ }
+
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsNotificationConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsNotificationConverter.java
new file mode 100644
index 0000000000..bb8aadfeb7
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsNotificationConverter.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.support.converter.SnsNotification;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+import org.springframework.core.GenericTypeResolver;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ResolvableType;
+import org.springframework.lang.Nullable;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.converter.SmartMessageConverter;
+import org.springframework.messaging.support.GenericMessage;
+import org.springframework.util.Assert;
+
+@Deprecated
+public class LegacyJackson2SnsNotificationConverter implements SmartMessageConverter {
+
+ private final ObjectMapper jsonMapper;
+
+ private final MessageConverter payloadConverter;
+
+ /**
+ * Creates a new converter with the given payload converter and JSON mapper.
+ * @param payloadConverter the converter to use for the message payload
+ * @param jsonMapper the JSON mapper to use for parsing the SNS notification
+ */
+ public LegacyJackson2SnsNotificationConverter(MessageConverter payloadConverter, ObjectMapper jsonMapper) {
+ Assert.notNull(payloadConverter, "payloadConverter must not be null");
+ Assert.notNull(jsonMapper, "jsonMapper must not be null");
+ this.payloadConverter = payloadConverter;
+ this.jsonMapper = jsonMapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object fromMessage(Message> message, Class> targetClass, @Nullable Object conversionHint) {
+ Assert.notNull(message, "message must not be null");
+ Assert.notNull(targetClass, "target class must not be null");
+
+ Object payload = message.getPayload();
+
+ if (payload instanceof List messages) {
+ return fromGenericMessages(messages, targetClass, conversionHint);
+ }
+ else {
+ return fromGenericMessage((GenericMessage>) message, targetClass, conversionHint);
+ }
+ }
+
+ private Object fromGenericMessages(List> messages, Class> targetClass,
+ @Nullable Object conversionHint) {
+ Type resolvedType = getResolvedType(targetClass, conversionHint);
+ Class> resolvedClazz = ResolvableType.forType(resolvedType).resolve();
+
+ Object hint = targetClass.isAssignableFrom(List.class) && conversionHint instanceof MethodParameter mp
+ ? mp.nested()
+ : conversionHint;
+
+ return messages.stream().map(message -> fromGenericMessage(message, resolvedClazz, hint)).toList();
+ }
+
+ private Object fromGenericMessage(GenericMessage> message, Class> targetClass,
+ @Nullable Object conversionHint) {
+ try {
+ Type payloadType = getPayloadType(targetClass, conversionHint);
+ Class> payloadClass = ResolvableType.forType(payloadType).resolve();
+
+ return jsonMapper.readValue(message.getPayload().toString(),
+ jsonMapper.getTypeFactory().constructParametricType(SnsNotification.class, payloadClass));
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException("Error converting SNS notification: " + e.getMessage(), e);
+ }
+ }
+
+ private Type getPayloadType(Class> targetClass, @Nullable Object conversionHint) {
+ if (conversionHint instanceof MethodParameter parameter) {
+ ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
+ if (resolvableType.isAssignableFrom(SnsNotification.class)) {
+ return resolvableType.getGeneric(0).getType();
+ }
+ }
+ return String.class;
+ }
+
+ @Override
+ public Object fromMessage(Message> message, Class> targetClass) {
+ return fromMessage(message, targetClass, null);
+ }
+
+ @Override
+ public Message> toMessage(Object payload, MessageHeaders headers) {
+ throw new UnsupportedOperationException(
+ "This converter only supports reading SNS notifications and not writing them");
+ }
+
+ @Override
+ public Message> toMessage(Object payload, MessageHeaders headers, Object conversionHint) {
+ throw new UnsupportedOperationException(
+ "This converter only supports reading SNS notifications and not writing them");
+ }
+
+ private static Type getResolvedType(Class> targetClass, @Nullable Object conversionHint) {
+ if (conversionHint instanceof MethodParameter param) {
+ param = param.nestedIfOptional();
+ if (Message.class.isAssignableFrom(param.getParameterType())) {
+ param = param.nested();
+ }
+ Type genericParameterType = param.getNestedGenericParameterType();
+ Class> contextClass = param.getContainingClass();
+ Type resolveType = GenericTypeResolver.resolveType(genericParameterType, contextClass);
+ if (resolveType instanceof ParameterizedType parameterizedType) {
+ return parameterizedType.getActualTypeArguments()[0];
+ }
+ else {
+ return resolveType;
+ }
+ }
+ return targetClass;
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsSubjectConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsSubjectConverter.java
new file mode 100644
index 0000000000..c9acc5603f
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacyJackson2SnsSubjectConverter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.List;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.converter.MessageConversionException;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * @author Alexander Nebel
+ * @since 3.3.1
+ */
+@Deprecated
+public class LegacyJackson2SnsSubjectConverter implements MessageConverter {
+
+ private final ObjectMapper objectMapper;
+
+ public LegacyJackson2SnsSubjectConverter(ObjectMapper objectMapper) {
+ Assert.notNull(objectMapper, "jsonMapper must not be null");
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public Object fromMessage(Message> message, Class> targetClass) {
+ Assert.notNull(message, "message must not be null");
+ Assert.notNull(targetClass, "target class must not be null");
+
+ Object payload = message.getPayload();
+
+ if (!ClassUtils.isAssignable(targetClass, String.class)) {
+ throw new MessageConversionException("Subject can only be injected into String assignable Types", null);
+ }
+ if (payload instanceof List) {
+ throw new MessageConversionException("Conversion of List is not supported", null);
+ }
+
+ var snsJsonNode = new LegacyJackson2SnsJsonNode(objectMapper, message.getPayload().toString());
+ return snsJsonNode.getSubjectAsString();
+ }
+
+ @Override
+ public Message> toMessage(Object payload, MessageHeaders headers) {
+ throw new UnsupportedOperationException(
+ "This converter only supports reading a SNS notification and not writing them");
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacySqsMessagingMessageConverter.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacySqsMessagingMessageConverter.java
new file mode 100644
index 0000000000..b1c9c7d109
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/converter/jackson2/LegacySqsMessagingMessageConverter.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.converter.jackson2;
+
+import static io.awspring.cloud.sqs.config.JacksonAbstractMessageConverterFactory.createDefaultMappingLegacyJackson2MessageConverter;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.support.converter.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.converter.CompositeMessageConverter;
+import org.springframework.messaging.converter.MappingJackson2MessageConverter;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.util.Assert;
+
+/**
+ * {@link MessagingMessageConverter} implementation for converting SQS
+ * {@link software.amazon.awssdk.services.sqs.model.Message} instances to Spring Messaging {@link Message} instances.
+ *
+ * @author Tomaz Fernandes
+ * @author Dongha kim
+ * @see SqsHeaderMapper
+ * @see SqsMessageConversionContext
+ * @since 3.0
+ */
+@Deprecated
+public class LegacySqsMessagingMessageConverter
+ extends AbstractMessagingMessageConverter {
+
+ public LegacySqsMessagingMessageConverter() {
+ this.payloadMessageConverter = createDefaultCompositeMessageConverter();
+ }
+
+ private CompositeMessageConverter createDefaultCompositeMessageConverter() {
+ List messageConverters = new ArrayList<>();
+ messageConverters.add(createClassMatchingMessageConverter());
+ messageConverters.add(createStringMessageConverter());
+ messageConverters.add(createDefaultMappingLegacyJackson2MessageConverter());
+ return new CompositeMessageConverter(messageConverters);
+ }
+
+ /**
+ * Set the {@link ObjectMapper} instance to be used for converting the {@link Message} instances payloads.
+ *
+ * @param objectMapper the object mapper instance.
+ */
+ public void setObjectMapper(ObjectMapper objectMapper) {
+ Assert.notNull(objectMapper, "messageConverter cannot be null");
+ MappingJackson2MessageConverter converter = getMappingJackson2MessageConverter().orElseThrow(
+ () -> new IllegalStateException("%s can only be set in %s instances, or %s containing one.".formatted(
+ ObjectMapper.class.getSimpleName(), MappingJackson2MessageConverter.class.getSimpleName(),
+ CompositeMessageConverter.class.getSimpleName())));
+ converter.setObjectMapper(objectMapper);
+ }
+
+ private Optional getMappingJackson2MessageConverter() {
+ return this.getPayloadMessageConverter() instanceof CompositeMessageConverter compositeConverter
+ ? compositeConverter.getConverters().stream()
+ .filter(converter -> converter instanceof MappingJackson2MessageConverter)
+ .map(MappingJackson2MessageConverter.class::cast).findFirst()
+ : this.getPayloadMessageConverter() instanceof MappingJackson2MessageConverter converter
+ ? Optional.of(converter)
+ : Optional.empty();
+ }
+
+ @Override
+ protected HeaderMapper createDefaultHeaderMapper() {
+ return new SqsHeaderMapper();
+ }
+
+ @Override
+ protected Object getPayloadToDeserialize(software.amazon.awssdk.services.sqs.model.Message message) {
+ return message.body();
+ }
+
+ @Override
+ public MessageConversionContext createMessageConversionContext() {
+ return new SqsMessageConversionContext();
+ }
+
+ @Override
+ protected software.amazon.awssdk.services.sqs.model.Message doConvertMessage(
+ software.amazon.awssdk.services.sqs.model.Message messageWithHeaders, Object payload) {
+ Assert.isInstanceOf(String.class, payload, "payload must be instance of String");
+ return messageWithHeaders.toBuilder().body((String) payload).build();
+ }
+
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationMessageArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationMessageArgumentResolver.java
index dd297f2172..e928b94489 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationMessageArgumentResolver.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationMessageArgumentResolver.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.resolver;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.annotation.SnsNotificationMessage;
import io.awspring.cloud.sqs.support.converter.SnsMessageConverter;
import org.springframework.core.MethodParameter;
@@ -23,6 +22,7 @@
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
+import tools.jackson.databind.json.JsonMapper;
/**
* @author Michael Sosa
@@ -34,7 +34,7 @@ public class NotificationMessageArgumentResolver implements HandlerMethodArgumen
private final SmartMessageConverter converter;
- public NotificationMessageArgumentResolver(MessageConverter converter, ObjectMapper jsonMapper) {
+ public NotificationMessageArgumentResolver(MessageConverter converter, JsonMapper jsonMapper) {
this.converter = new SnsMessageConverter(converter, jsonMapper);
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationSubjectArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationSubjectArgumentResolver.java
index ba7a1770cf..a608f00557 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationSubjectArgumentResolver.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/NotificationSubjectArgumentResolver.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.resolver;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.annotation.SnsNotificationSubject;
import io.awspring.cloud.sqs.support.converter.SnsSubjectConverter;
import java.lang.reflect.Executable;
@@ -27,6 +26,7 @@
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.util.ClassUtils;
+import tools.jackson.databind.json.JsonMapper;
/**
* @author Alexander Nebel
@@ -38,7 +38,7 @@ public class NotificationSubjectArgumentResolver implements HandlerMethodArgumen
private final MessageConverter converter;
- public NotificationSubjectArgumentResolver(ObjectMapper jsonMapper) {
+ public NotificationSubjectArgumentResolver(JsonMapper jsonMapper) {
this.converter = new SnsSubjectConverter(jsonMapper);
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolver.java
index 2524cb3a6f..1afaa846e1 100644
--- a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolver.java
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolver.java
@@ -15,7 +15,6 @@
*/
package io.awspring.cloud.sqs.support.resolver;
-import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.sqs.support.converter.SnsNotification;
import io.awspring.cloud.sqs.support.converter.SnsNotificationConverter;
import org.springframework.core.MethodParameter;
@@ -23,6 +22,7 @@
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SmartMessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
+import tools.jackson.databind.json.JsonMapper;
/**
* Resolves method parameters with {@link SnsNotification} object.
@@ -39,7 +39,7 @@ public class SnsNotificationArgumentResolver implements HandlerMethodArgumentRes
* @param converter the message converter to use for the message payload
* @param jsonMapper the JSON mapper to use for parsing the SNS notification
*/
- public SnsNotificationArgumentResolver(MessageConverter converter, ObjectMapper jsonMapper) {
+ public SnsNotificationArgumentResolver(MessageConverter converter, JsonMapper jsonMapper) {
this.converter = new SnsNotificationConverter(converter, jsonMapper);
}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2NotificationMessageArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2NotificationMessageArgumentResolver.java
new file mode 100644
index 0000000000..8c093fb0e9
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2NotificationMessageArgumentResolver.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.resolver.jacskon2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.annotation.SnsNotificationMessage;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2SnsMessageConverter;
+import org.springframework.core.MethodParameter;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.converter.SmartMessageConverter;
+import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
+
+/**
+ * @author Michael Sosa
+ * @author gustavomonarin
+ * @author Wei Jiang
+ * @since 3.1.1
+ */
+@Deprecated
+public class LegacyJackson2NotificationMessageArgumentResolver implements HandlerMethodArgumentResolver {
+
+ private final SmartMessageConverter converter;
+
+ public LegacyJackson2NotificationMessageArgumentResolver(MessageConverter converter, ObjectMapper jsonMapper) {
+ this.converter = new LegacyJackson2SnsMessageConverter(converter, jsonMapper);
+ }
+
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ return parameter.hasParameterAnnotation(SnsNotificationMessage.class);
+ }
+
+ @Override
+ public Object resolveArgument(MethodParameter par, Message> msg) {
+ return this.converter.fromMessage(msg, par.getParameterType(), par);
+ }
+
+}
diff --git a/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2SnsNotificationArgumentResolver.java b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2SnsNotificationArgumentResolver.java
new file mode 100644
index 0000000000..b7565a89a8
--- /dev/null
+++ b/spring-cloud-aws-sqs/src/main/java/io/awspring/cloud/sqs/support/resolver/jacskon2/LegacyJackson2SnsNotificationArgumentResolver.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.awspring.cloud.sqs.support.resolver.jacskon2;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.support.converter.SnsNotification;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2SnsNotificationConverter;
+import org.springframework.core.MethodParameter;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.converter.SmartMessageConverter;
+import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
+
+@Deprecated
+public class LegacyJackson2SnsNotificationArgumentResolver implements HandlerMethodArgumentResolver {
+
+ private final SmartMessageConverter converter;
+
+ /**
+ * Creates a new resolver with the given converter and JSON mapper.
+ * @param converter the message converter to use for the message payload
+ * @param jsonMapper the JSON mapper to use for parsing the SNS notification
+ */
+ public LegacyJackson2SnsNotificationArgumentResolver(MessageConverter converter, ObjectMapper jsonMapper) {
+ this.converter = new LegacyJackson2SnsNotificationConverter(converter, jsonMapper);
+ }
+
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ return SnsNotification.class.isAssignableFrom(parameter.getParameterType());
+ }
+
+ @Override
+ public Object resolveArgument(MethodParameter parameter, Message> message) {
+ return this.converter.fromMessage(message, parameter.getParameterType(), parameter);
+ }
+}
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessorTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessorTests.java
index 6919699a65..b8240eff80 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessorTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/annotation/SqsListenerAnnotationBeanPostProcessorTests.java
@@ -25,15 +25,11 @@
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
-import io.awspring.cloud.sqs.config.Endpoint;
-import io.awspring.cloud.sqs.config.EndpointRegistrar;
-import io.awspring.cloud.sqs.config.MessageListenerContainerFactory;
-import io.awspring.cloud.sqs.config.MultiMethodSqsEndpoint;
-import io.awspring.cloud.sqs.config.SqsBeanNames;
-import io.awspring.cloud.sqs.config.SqsListenerConfigurer;
+import io.awspring.cloud.sqs.config.*;
import io.awspring.cloud.sqs.listener.DefaultListenerContainerRegistry;
import io.awspring.cloud.sqs.listener.MessageListenerContainer;
import io.awspring.cloud.sqs.listener.MessageListenerContainerRegistry;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
import io.awspring.cloud.sqs.support.resolver.BatchPayloadMethodArgumentResolver;
import java.util.ArrayList;
import java.util.Collections;
@@ -81,7 +77,7 @@ public void registerListenerContainer(MessageListenerContainer> listenerContai
registrar.setDefaultListenerContainerFactoryBeanName(factoryName);
registrar.setListenerContainerRegistry(registry);
registrar.setMessageHandlerMethodFactory(methodFactory);
- registrar.setObjectMapper(objectMapper);
+ registrar.setJacksonMapperWrapper(new LegacyJackson2MessageConverterFactory(objectMapper));
registrar.manageMessageConverters(converters -> converters.add(converter));
registrar.manageMethodArgumentResolvers(resolvers -> resolvers.add(resolver));
registrar.setValidator(validator);
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SnsNotificationIntegrationTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SnsNotificationIntegrationTests.java
index 8a10df716f..ed8ba89b07 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SnsNotificationIntegrationTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SnsNotificationIntegrationTests.java
@@ -28,6 +28,7 @@
import io.awspring.cloud.sqs.listener.acknowledgement.AcknowledgementResultCallback;
import io.awspring.cloud.sqs.operations.SqsTemplate;
import io.awspring.cloud.sqs.support.converter.SnsNotification;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
@@ -358,7 +359,8 @@ ObjectMapper objectMapper() {
@Bean
SqsListenerConfigurer sqsListenerConfigurer(ObjectMapper objectMapper) {
- return registrar -> registrar.setObjectMapper(objectMapper);
+ return registrar -> registrar
+ .setJacksonMapperWrapper(new LegacyJackson2MessageConverterFactory(objectMapper));
}
@Bean
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SqsMessageConversionIntegrationTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SqsMessageConversionIntegrationTests.java
index 37d5070dee..bdd1f0231f 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SqsMessageConversionIntegrationTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/integration/SqsMessageConversionIntegrationTests.java
@@ -28,6 +28,7 @@
import io.awspring.cloud.sqs.listener.interceptor.AsyncMessageInterceptor;
import io.awspring.cloud.sqs.operations.SqsTemplate;
import io.awspring.cloud.sqs.support.converter.MessagingMessageHeaders;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
@@ -423,7 +424,8 @@ ObjectMapper objectMapper() {
@Bean
SqsListenerConfigurer customizer(ObjectMapper objectMapper) {
- return registrar -> registrar.setObjectMapper(objectMapper);
+ return registrar -> registrar
+ .setJacksonMapperWrapper(new LegacyJackson2MessageConverterFactory(new ObjectMapper()));
}
@Bean
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/AbstractPollingMessageSourceTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/AbstractPollingMessageSourceTests.java
index a3f850eded..7d3d9a8165 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/AbstractPollingMessageSourceTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/AbstractPollingMessageSourceTests.java
@@ -33,7 +33,7 @@
import io.awspring.cloud.sqs.listener.backpressure.ConcurrencyLimiterBlockingBackPressureHandler;
import io.awspring.cloud.sqs.listener.backpressure.ThroughputBackPressureHandler;
import io.awspring.cloud.sqs.support.converter.MessageConversionContext;
-import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
@@ -308,7 +308,7 @@ void shouldReleasePermitsOnConversionErrors() {
String testName = "shouldReleasePermitsOnConversionErrors";
AtomicInteger convertedMessages = new AtomicInteger(0);
- var converter = new SqsMessagingMessageConverter() {
+ var converter = new LegacySqsMessagingMessageConverter() {
@Override
public org.springframework.messaging.Message> toMessagingMessage(Message source,
@Nullable MessageConversionContext context) {
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/SemaphoreBackPressureHandlerAbstractPollingMessageSourceTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/SemaphoreBackPressureHandlerAbstractPollingMessageSourceTests.java
index b40951fed8..1886406f57 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/SemaphoreBackPressureHandlerAbstractPollingMessageSourceTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/listener/source/SemaphoreBackPressureHandlerAbstractPollingMessageSourceTests.java
@@ -29,7 +29,7 @@
import io.awspring.cloud.sqs.listener.backpressure.BackPressureHandler;
import io.awspring.cloud.sqs.listener.backpressure.BackPressureHandlerFactories;
import io.awspring.cloud.sqs.support.converter.MessageConversionContext;
-import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
@@ -254,7 +254,7 @@ void shouldReleasePermitsOnConversionErrors() {
AtomicInteger messagesInSink = new AtomicInteger(0);
AtomicBoolean hasFailed = new AtomicBoolean(false);
- var converter = new SqsMessagingMessageConverter() {
+ var converter = new LegacySqsMessagingMessageConverter() {
@Override
public org.springframework.messaging.Message> toMessagingMessage(Message source,
@Nullable MessageConversionContext context) {
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverterTests.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/LegacySqsMessagingMessageConverterTests.java
similarity index 89%
rename from spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverterTests.java
rename to spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/LegacySqsMessagingMessageConverterTests.java
index 2043a3b423..fd0aaed937 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SqsMessagingMessageConverterTests.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/LegacySqsMessagingMessageConverterTests.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
+import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
import java.util.Collections;
import java.util.Objects;
import java.util.UUID;
@@ -34,11 +35,11 @@
import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
/**
- * Tests for {@link SqsMessagingMessageConverter}.
+ * Tests for {@link LegacySqsMessagingMessageConverter}.
*
* @author Tomaz Fernandes
*/
-class SqsMessagingMessageConverterTests {
+class LegacySqsMessagingMessageConverterTests {
private final ObjectMapper objectMapper = new ObjectMapper();
@@ -47,7 +48,7 @@ void shouldUseProvidedTypeMapper() throws Exception {
MyPojo myPojo = new MyPojo();
String payload = new ObjectMapper().writeValueAsString(myPojo);
Message message = Message.builder().body(payload).messageId(UUID.randomUUID().toString()).build();
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
converter.setPayloadTypeMapper(msg -> MyPojo.class);
org.springframework.messaging.Message> resultMessage = converter.toMessagingMessage(message);
assertThat(resultMessage.getPayload()).isEqualTo(myPojo);
@@ -63,7 +64,7 @@ void shouldUseProvidedTypeHeader() throws Exception {
MessageAttributeValue.builder().dataType(MessageAttributeDataTypes.STRING)
.stringValue(MyPojo.class.getName()).build()))
.body(payload).messageId(UUID.randomUUID().toString()).build();
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
converter.setPayloadTypeHeader(typeHeader);
org.springframework.messaging.Message> resultMessage = converter.toMessagingMessage(message);
assertThat(resultMessage.getPayload()).isEqualTo(myPojo);
@@ -79,7 +80,7 @@ void shouldUseHeaderOverPayloadClass() throws Exception {
MessageAttributeValue.builder().dataType(MessageAttributeDataTypes.STRING)
.stringValue(MyPojo.class.getName()).build()))
.body(payload).messageId(UUID.randomUUID().toString()).build();
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
SqsMessageConversionContext context = new SqsMessageConversionContext();
context.setPayloadClass(String.class);
converter.setPayloadTypeHeader(typeHeader);
@@ -91,7 +92,7 @@ void shouldUseHeaderOverPayloadClass() throws Exception {
@Test
void shouldUseProvidedHeaderMapper() {
Message message = Message.builder().body("test-payload").messageId(UUID.randomUUID().toString()).build();
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
HeaderMapper mapper = mock(HeaderMapper.class);
MessageHeaders messageHeaders = new MessageHeaders(Collections.singletonMap("testHeader", "testHeaderValue"));
given(mapper.toHeaders(message)).willReturn(messageHeaders);
@@ -108,7 +109,7 @@ void shouldUseProvidedPayloadConverter() throws Exception {
MessageConverter payloadConverter = mock(MessageConverter.class);
when(payloadConverter.fromMessage(any(org.springframework.messaging.Message.class), eq(MyPojo.class)))
.thenReturn(myPojo);
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
converter.setPayloadMessageConverter(payloadConverter);
converter.setPayloadTypeMapper(msg -> MyPojo.class);
org.springframework.messaging.Message> resultMessage = converter.toMessagingMessage(message);
@@ -122,7 +123,7 @@ void shouldUseHeadersFromPayloadConverter() {
.setHeader("contentType", "application/json").build();
when(payloadConverter.toMessage(any(MyPojo.class), any())).thenReturn(convertedMessageWithContentType);
- SqsMessagingMessageConverter converter = new SqsMessagingMessageConverter();
+ LegacySqsMessagingMessageConverter converter = new LegacySqsMessagingMessageConverter();
converter.setPayloadMessageConverter(payloadConverter);
converter.setPayloadTypeMapper(msg -> MyPojo.class);
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverterTest.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverterTest.java
index 7dba92bb19..fa163a8c5c 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverterTest.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/converter/SnsNotificationConverterTest.java
@@ -31,6 +31,7 @@
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.support.GenericMessage;
+import tools.jackson.databind.json.JsonMapper;
/**
* Tests for {@link SnsNotificationConverter}.
@@ -52,7 +53,7 @@ class SnsNotificationConverterTest {
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
- converter = new SnsNotificationConverter(payloadConverter, objectMapper);
+ converter = new SnsNotificationConverter(payloadConverter, new JsonMapper());
}
@Test
diff --git a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolverTest.java b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolverTest.java
index ff66313843..efffbed7ce 100644
--- a/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolverTest.java
+++ b/spring-cloud-aws-sqs/src/test/java/io/awspring/cloud/sqs/support/resolver/SnsNotificationArgumentResolverTest.java
@@ -31,6 +31,7 @@
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.support.GenericMessage;
+import tools.jackson.databind.json.JsonMapper;
/**
* Tests for {@link SnsNotificationArgumentResolver}.
@@ -49,7 +50,7 @@ class SnsNotificationArgumentResolverTest {
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
- resolver = new SnsNotificationArgumentResolver(messageConverter, objectMapper);
+ resolver = new SnsNotificationArgumentResolver(messageConverter, new JsonMapper());
}
@Test
diff --git a/spring-cloud-aws-test/pom.xml b/spring-cloud-aws-test/pom.xml
index 3ba8da6973..cb0543cea3 100644
--- a/spring-cloud-aws-test/pom.xml
+++ b/spring-cloud-aws-test/pom.xml
@@ -57,6 +57,11 @@
org.junit.jupiter
junit-jupiter-api
+
+ tools.jackson.core
+ jackson-databind
+ test
+
org.assertj
diff --git a/spring-cloud-aws-testcontainers/pom.xml b/spring-cloud-aws-testcontainers/pom.xml
index 3f9f103a15..4bf12c184c 100644
--- a/spring-cloud-aws-testcontainers/pom.xml
+++ b/spring-cloud-aws-testcontainers/pom.xml
@@ -23,6 +23,11 @@
io.awspring.cloud
spring-cloud-aws-core
+
+ tools.jackson.core
+ jackson-databind
+ test
+
org.springframework.boot
spring-boot-testcontainers