Skip to content

Commit f37c006

Browse files
committed
Initial set of implementation
1 parent a0456f4 commit f37c006

File tree

49 files changed

+1522
-286
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1522
-286
lines changed

spring-cloud-aws-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@
7676
<artifactId>spring-cloud-aws-ses</artifactId>
7777
<optional>true</optional>
7878
</dependency>
79+
<dependency>
80+
<groupId>tools.jackson.core</groupId>
81+
<artifactId>jackson-databind</artifactId>
82+
<optional>true</optional>
83+
</dependency>
7984
<dependency>
8085
<groupId>io.awspring.cloud</groupId>
8186
<artifactId>spring-cloud-aws-sns</artifactId>

spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,20 @@
1616
package io.awspring.cloud.autoconfigure.s3;
1717

1818
import com.fasterxml.jackson.databind.ObjectMapper;
19-
import com.fasterxml.jackson.databind.json.JsonMapper;
2019
import io.awspring.cloud.autoconfigure.AwsSyncClientCustomizer;
2120
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
2221
import io.awspring.cloud.autoconfigure.core.AwsConnectionDetails;
2322
import io.awspring.cloud.autoconfigure.core.AwsProperties;
2423
import io.awspring.cloud.autoconfigure.s3.properties.S3Properties;
25-
import io.awspring.cloud.core.support.JacksonPresent;
2624
import io.awspring.cloud.s3.*;
27-
2825
import java.util.Optional;
2926
import org.springframework.beans.factory.ObjectProvider;
3027
import org.springframework.boot.autoconfigure.AutoConfiguration;
31-
import org.springframework.boot.autoconfigure.condition.*;
28+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3233
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3334
import org.springframework.boot.context.properties.PropertyMapper;
3435
import org.springframework.context.annotation.Bean;
@@ -44,6 +45,7 @@
4445
import software.amazon.awssdk.services.s3.S3ClientBuilder;
4546
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
4647
import software.amazon.encryption.s3.S3EncryptionClient;
48+
import tools.jackson.databind.json.JsonMapper;
4749

4850
/**
4951
* {@link AutoConfiguration} for {@link S3Client} and {@link S3ProtocolResolver}.
@@ -119,11 +121,50 @@ else if (awsProperties.getEndpoint() != null) {
119121
return builder.build();
120122
}
121123

124+
@Bean
125+
@ConditionalOnMissingBean
126+
S3Client s3Client(S3ClientBuilder s3ClientBuilder) {
127+
return s3ClientBuilder.build();
128+
}
129+
130+
@Bean
131+
@ConditionalOnMissingBean
132+
S3OutputStreamProvider inMemoryBufferingS3StreamProvider(S3Client s3Client,
133+
Optional<S3ObjectContentTypeResolver> contentTypeResolver) {
134+
return new InMemoryBufferingS3OutputStreamProvider(s3Client,
135+
contentTypeResolver.orElseGet(PropertiesS3ObjectContentTypeResolver::new));
136+
}
137+
122138
@Conditional(S3EncryptionConditional.class)
123139
@ConditionalOnClass(name = "software.amazon.encryption.s3.S3EncryptionClient")
124140
@Configuration
125141
public static class S3EncryptionConfiguration {
126142

143+
private static void configureEncryptionProperties(S3Properties properties,
144+
ObjectProvider<S3RsaProvider> rsaProvider, ObjectProvider<S3AesProvider> aesProvider,
145+
S3EncryptionClient.Builder builder) {
146+
PropertyMapper propertyMapper = PropertyMapper.get();
147+
var encryptionProperties = properties.getEncryption();
148+
149+
propertyMapper.from(encryptionProperties::isEnableDelayedAuthenticationMode)
150+
.to(builder::enableDelayedAuthenticationMode);
151+
propertyMapper.from(encryptionProperties::isEnableLegacyUnauthenticatedModes)
152+
.to(builder::enableLegacyUnauthenticatedModes);
153+
propertyMapper.from(encryptionProperties::isEnableMultipartPutObject).to(builder::enableMultipartPutObject);
154+
155+
if (!StringUtils.hasText(properties.getEncryption().getKeyId())) {
156+
if (aesProvider.getIfAvailable() != null) {
157+
builder.aesKey(aesProvider.getObject().generateSecretKey());
158+
}
159+
else {
160+
builder.rsaKeyPair(rsaProvider.getObject().generateKeyPair());
161+
}
162+
}
163+
else {
164+
propertyMapper.from(encryptionProperties::getKeyId).to(builder::kmsKeyId);
165+
}
166+
}
167+
127168
@Bean
128169
@ConditionalOnMissingBean
129170
S3Client s3EncryptionClient(S3EncryptionClient.Builder s3EncryptionBuilder, S3ClientBuilder s3ClientBuilder) {
@@ -149,62 +190,28 @@ S3EncryptionClient.Builder s3EncrpytionClientBuilder(S3Properties properties,
149190
configureEncryptionProperties(properties, rsaProvider, aesProvider, builder);
150191
return builder;
151192
}
193+
}
152194

153-
private static void configureEncryptionProperties(S3Properties properties,
154-
ObjectProvider<S3RsaProvider> rsaProvider, ObjectProvider<S3AesProvider> aesProvider,
155-
S3EncryptionClient.Builder builder) {
156-
PropertyMapper propertyMapper = PropertyMapper.get();
157-
var encryptionProperties = properties.getEncryption();
158-
159-
propertyMapper.from(encryptionProperties::isEnableDelayedAuthenticationMode)
160-
.to(builder::enableDelayedAuthenticationMode);
161-
propertyMapper.from(encryptionProperties::isEnableLegacyUnauthenticatedModes)
162-
.to(builder::enableLegacyUnauthenticatedModes);
163-
propertyMapper.from(encryptionProperties::isEnableMultipartPutObject).to(builder::enableMultipartPutObject);
195+
@Configuration
196+
@AutoConfigureAfter(Jackson2JsonS3ObjectConverterConfiguration.class)
197+
@ConditionalOnClass(value = ObjectMapper.class)
198+
static class LegacyJackson2JsonS3ObjectConverterConfiguration {
164199

165-
if (!StringUtils.hasText(properties.getEncryption().getKeyId())) {
166-
if (aesProvider.getIfAvailable() != null) {
167-
builder.aesKey(aesProvider.getObject().generateSecretKey());
168-
}
169-
else {
170-
builder.rsaKeyPair(rsaProvider.getObject().generateKeyPair());
171-
}
172-
}
173-
else {
174-
propertyMapper.from(encryptionProperties::getKeyId).to(builder::kmsKeyId);
175-
}
200+
@ConditionalOnMissingBean
201+
@Bean
202+
S3ObjectConverter s3ObjectConverter(Optional<ObjectMapper> objectMapper) {
203+
return new LegacyJackson2JsonS3ObjectConverter(objectMapper.orElseGet(ObjectMapper::new));
176204
}
177205
}
178206

179-
@Bean
180-
@ConditionalOnMissingBean
181-
S3Client s3Client(S3ClientBuilder s3ClientBuilder) {
182-
return s3ClientBuilder.build();
183-
}
184-
185207
@Configuration
186-
@ConditionalOnClass(ObjectMapper.class)
208+
@ConditionalOnClass(value = JsonMapper.class)
187209
static class Jackson2JsonS3ObjectConverterConfiguration {
188210

189211
@ConditionalOnMissingBean
190212
@Bean
191-
S3ObjectConverter s3ObjectConverter(Optional<JsonMapper> jsonMapper, Optional<ObjectMapper> objectMapper) {
192-
if (JacksonPresent.isJackson2Present()) {
193-
return new LegacyJackson2JsonS3ObjectConverter(objectMapper.orElseGet(ObjectMapper::new));
194-
} else if (JacksonPresent.isJackson3Present()) {
195-
return new Jackson2JsonS3ObjectConverter(jsonMapper.orElseGet(JsonMapper::new));
196-
} else {
197-
throw new IllegalStateException(
198-
"SecretsManagerPropertySource requires a Jackson 2 or Jackson 3 library on the classpath");
199-
}
213+
S3ObjectConverter s3ObjectConverter(Optional<JsonMapper> jsonMapper) {
214+
return new Jackson2JsonS3ObjectConverter(jsonMapper.orElseGet(JsonMapper::new));
200215
}
201216
}
202-
203-
@Bean
204-
@ConditionalOnMissingBean
205-
S3OutputStreamProvider inMemoryBufferingS3StreamProvider(S3Client s3Client,
206-
Optional<S3ObjectContentTypeResolver> contentTypeResolver) {
207-
return new InMemoryBufferingS3OutputStreamProvider(s3Client,
208-
contentTypeResolver.orElseGet(PropertiesS3ObjectContentTypeResolver::new));
209-
}
210217
}

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

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package io.awspring.cloud.autoconfigure.sqs;
1717

18-
import com.fasterxml.jackson.databind.ObjectMapper;
1918
import io.awspring.cloud.autoconfigure.AwsAsyncClientCustomizer;
2019
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
2120
import io.awspring.cloud.autoconfigure.core.AwsConnectionDetails;
@@ -31,8 +30,12 @@
3130
import io.awspring.cloud.sqs.listener.interceptor.MessageInterceptor;
3231
import io.awspring.cloud.sqs.operations.SqsTemplate;
3332
import io.awspring.cloud.sqs.operations.SqsTemplateBuilder;
33+
import io.awspring.cloud.sqs.support.converter.AbstractMessageConverterFactory;
34+
import io.awspring.cloud.sqs.support.converter.JacksonJsonMessageConverterFactory;
3435
import io.awspring.cloud.sqs.support.converter.MessagingMessageConverter;
3536
import io.awspring.cloud.sqs.support.converter.SqsMessagingMessageConverter;
37+
import io.awspring.cloud.sqs.support.converter.jackson2.LegacyJackson2MessageConverterFactory;
38+
import io.awspring.cloud.sqs.support.converter.jackson2.LegacySqsMessagingMessageConverter;
3639
import io.awspring.cloud.sqs.support.observation.SqsListenerObservation;
3740
import io.awspring.cloud.sqs.support.observation.SqsTemplateObservation;
3841
import io.micrometer.observation.ObservationRegistry;
@@ -49,6 +52,7 @@
4952
import org.springframework.context.annotation.Import;
5053
import software.amazon.awssdk.services.sqs.SqsAsyncClient;
5154
import software.amazon.awssdk.services.sqs.model.Message;
55+
import tools.jackson.databind.json.JsonMapper;
5256

5357
/**
5458
* {@link EnableAutoConfiguration Auto-configuration} for SQS integration.
@@ -87,7 +91,8 @@ public SqsAsyncClient sqsAsyncClient(AwsClientBuilderConfigurer awsClientBuilder
8791

8892
@ConditionalOnMissingBean
8993
@Bean
90-
public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient, ObjectProvider<ObjectMapper> objectMapperProvider,
94+
public SqsTemplate sqsTemplate(SqsAsyncClient sqsAsyncClient,
95+
ObjectProvider<AbstractMessageConverterFactory> objectMapperProvider,
9196
ObjectProvider<ObservationRegistry> observationRegistryProvider,
9297
ObjectProvider<SqsTemplateObservation.Convention> observationConventionProvider,
9398
MessagingMessageConverter<Message> messageConverter) {
@@ -114,7 +119,8 @@ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFac
114119
ObjectProvider<AsyncMessageInterceptor<Object>> asyncInterceptors,
115120
ObjectProvider<ObservationRegistry> observationRegistry,
116121
ObjectProvider<SqsListenerObservation.Convention> observationConventionProvider,
117-
ObjectProvider<MessageInterceptor<Object>> interceptors, ObjectProvider<ObjectMapper> objectMapperProvider,
122+
ObjectProvider<MessageInterceptor<Object>> interceptors,
123+
ObjectProvider<AbstractMessageConverterFactory> objectMapperProvider,
118124
MessagingMessageConverter<?> messagingMessageConverter) {
119125

120126
SqsMessageListenerContainerFactory<Object> factory = new SqsMessageListenerContainerFactory<>();
@@ -135,18 +141,13 @@ public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFac
135141
return factory;
136142
}
137143

138-
private void setMapperToConverter(MessagingMessageConverter<?> messagingMessageConverter, ObjectMapper om) {
139-
if (messagingMessageConverter instanceof SqsMessagingMessageConverter sqsConverter) {
140-
sqsConverter.setObjectMapper(om);
144+
private void setMapperToConverter(MessagingMessageConverter<?> messagingMessageConverter,
145+
AbstractMessageConverterFactory factory) {
146+
if (messagingMessageConverter instanceof LegacySqsMessagingMessageConverter sqsConverter) {
147+
sqsConverter.setObjectMapper(((LegacyJackson2MessageConverterFactory) factory).getObjectMapper());
141148
}
142149
}
143150

144-
@ConditionalOnMissingBean
145-
@Bean
146-
public MessagingMessageConverter<Message> messageConverter() {
147-
return new SqsMessagingMessageConverter();
148-
}
149-
150151
private void configureProperties(SqsContainerOptionsBuilder options) {
151152
PropertyMapper mapper = PropertyMapper.get();
152153
mapper.from(this.sqsProperties.getQueueNotFoundStrategy()).to(options::queueNotFoundStrategy);
@@ -157,13 +158,26 @@ private void configureProperties(SqsContainerOptionsBuilder options) {
157158
mapper.from(this.sqsProperties.getListener().getAutoStartup()).to(options::autoStartup);
158159
}
159160

161+
@ConditionalOnMissingBean
162+
@Bean
163+
public MessagingMessageConverter<Message> messageConverter() {
164+
return new SqsMessagingMessageConverter();
165+
}
166+
167+
@Bean
168+
@ConditionalOnMissingBean
169+
public AbstractMessageConverterFactory jsonMapperWrapper(ObjectProvider<JsonMapper> jsonMapper) {
170+
JsonMapper mapper = jsonMapper.getIfAvailable(JsonMapper::new);
171+
return new JacksonJsonMessageConverterFactory(mapper);
172+
}
173+
160174
@Bean
161-
public SqsListenerConfigurer objectMapperCustomizer(ObjectProvider<ObjectMapper> objectMapperProvider) {
162-
ObjectMapper objectMapper = objectMapperProvider.getIfUnique();
175+
public SqsListenerConfigurer objectMapperCustomizer(
176+
ObjectProvider<AbstractMessageConverterFactory> objectProviderWrapper) {
177+
AbstractMessageConverterFactory wrapper = objectProviderWrapper.getIfUnique();
163178
return registrar -> {
164-
// Object Mapper for SqsListener annotations handler method
165-
if (registrar.getObjectMapper() == null && objectMapper != null) {
166-
registrar.setObjectMapper(objectMapper);
179+
if (wrapper != null) {
180+
registrar.setJacksonMapperWrapper(wrapper);
167181
}
168182
};
169183
}

spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfigurationTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
5555
import software.amazon.awssdk.utils.AttributeMap;
5656
import software.amazon.encryption.s3.S3EncryptionClient;
57+
import tools.jackson.databind.json.JsonMapper;
5758

5859
/**
5960
* Tests for {@link S3AutoConfiguration}.
@@ -237,7 +238,9 @@ void withJacksonOnClasspathAutoconfiguresObjectConverter() {
237238

238239
@Test
239240
void withoutJacksonOnClasspathDoesNotConfigureObjectConverter() {
240-
contextRunner.withClassLoader(new FilteredClassLoader(ObjectMapper.class, S3EncryptionClient.class))
241+
contextRunner
242+
.withClassLoader(
243+
new FilteredClassLoader(JsonMapper.class, ObjectMapper.class, S3EncryptionClient.class))
241244
.run(context -> {
242245
assertThat(context).doesNotHaveBean(S3ObjectConverter.class);
243246
assertThat(context).doesNotHaveBean(S3Template.class);
@@ -248,8 +251,7 @@ void withoutJacksonOnClasspathDoesNotConfigureObjectConverter() {
248251
void usesCustomObjectMapperBean() {
249252
contextRunner.withUserConfiguration(CustomJacksonConfiguration.class).run(context -> {
250253
S3ObjectConverter s3ObjectConverter = context.getBean(S3ObjectConverter.class);
251-
assertThat(s3ObjectConverter).extracting("objectMapper")
252-
.isEqualTo(context.getBean("customObjectMapper"));
254+
assertThat(s3ObjectConverter).extracting("jsonMapper").isEqualTo(context.getBean("customJsonMapper"));
253255
});
254256
}
255257

@@ -347,8 +349,8 @@ void setsRegionToDefault() {
347349
@Configuration(proxyBeanMethods = false)
348350
static class CustomJacksonConfiguration {
349351
@Bean
350-
ObjectMapper customObjectMapper() {
351-
return new ObjectMapper();
352+
JsonMapper customJsonMapper() {
353+
return new JsonMapper();
352354
}
353355
}
354356

0 commit comments

Comments
 (0)