Skip to content

Commit 90caa2e

Browse files
committed
GH-1210 Add S3EventSerializer logic to ensure S3Event deserialization
Resolves #1210
1 parent 0a43fc9 commit 90caa2e

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<properties>
2020
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2121
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
22-
<aws-lambda-events.version>3.11.4</aws-lambda-events.version>
22+
<aws-lambda-events.version>3.14.0</aws-lambda-events.version>
2323
<aws-java-sdk.version>1.12.29</aws-java-sdk.version>
2424
<aws-lambda-java-log4j.version>1.0.1</aws-lambda-java-log4j.version>
2525
<aws-lambda-java-serialization.version>1.1.5</aws-lambda-java-serialization.version>

spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/AWSTypesMessageConverter.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
package org.springframework.cloud.function.adapter.aws;
1818

1919
import java.io.ByteArrayInputStream;
20+
import java.io.ByteArrayOutputStream;
2021
import java.nio.charset.StandardCharsets;
2122
import java.util.Map;
23+
import java.util.concurrent.atomic.AtomicReference;
2224

2325
import com.amazonaws.services.lambda.runtime.serialization.PojoSerializer;
2426
import com.amazonaws.services.lambda.runtime.serialization.events.LambdaEventSerializers;
27+
import com.amazonaws.services.lambda.runtime.serialization.events.serializers.S3EventSerializer;
2528

2629
import org.springframework.cloud.function.cloudevent.CloudEventMessageUtils;
2730
import org.springframework.cloud.function.context.config.JsonMessageConverter;
@@ -30,6 +33,7 @@
3033
import org.springframework.messaging.Message;
3134
import org.springframework.messaging.MessageHeaders;
3235
import org.springframework.messaging.converter.MessageConverter;
36+
import org.springframework.util.ClassUtils;
3337
import org.springframework.util.MimeType;
3438

3539
/**
@@ -44,6 +48,9 @@ class AWSTypesMessageConverter extends JsonMessageConverter {
4448

4549
private final JsonMapper jsonMapper;
4650

51+
@SuppressWarnings("rawtypes")
52+
private final AtomicReference<S3EventSerializer> s3EventSerializer = new AtomicReference<>();
53+
4754
AWSTypesMessageConverter(JsonMapper jsonMapper) {
4855
this(jsonMapper, new MimeType("application", "json"), new MimeType(CloudEventMessageUtils.APPLICATION_CLOUDEVENTS.getType(),
4956
CloudEventMessageUtils.APPLICATION_CLOUDEVENTS.getSubtype() + "+json"));
@@ -75,7 +82,6 @@ protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @
7582
if (message.getPayload().getClass().isAssignableFrom(targetClass)) {
7683
return message.getPayload();
7784
}
78-
7985
if (targetClass.getPackage() != null &&
8086
targetClass.getPackage().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) {
8187
PojoSerializer<?> serializer = LambdaEventSerializers.serializerFor(targetClass, Thread.currentThread().getContextClassLoader());
@@ -110,12 +116,23 @@ protected boolean canConvertTo(Object payload, @Nullable MessageHeaders headers)
110116
}
111117

112118

119+
@SuppressWarnings("unchecked")
113120
@Override
114121
protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers,
115122
@Nullable Object conversionHint) {
116123
if (payload instanceof String && headers.containsKey(AWSLambdaUtils.IS_BASE64_ENCODED) && (boolean) headers.get(AWSLambdaUtils.IS_BASE64_ENCODED)) {
117124
return ((String) payload).getBytes(StandardCharsets.UTF_8);
118125
}
126+
if (payload.getClass().getName().equals("com.amazonaws.services.lambda.runtime.events.S3Event")) {
127+
if (this.s3EventSerializer.get() == null) {
128+
this.s3EventSerializer.set(new S3EventSerializer<>().withClassLoader(ClassUtils.getDefaultClassLoader()));
129+
}
130+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
131+
this.s3EventSerializer.get().toJson(payload, stream);
132+
return stream.toByteArray();
133+
}
134+
135+
119136
return jsonMapper.toJson(payload);
120137
}
121138

spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/FunctionInvokerTests.java

+19
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,18 @@ public void testS3StringEvent() throws Exception {
999999
assertThat(result).contains("s3SchemaVersion");
10001000
}
10011001

1002+
@Test
1003+
public void testS3EventAsOutput() throws Exception {
1004+
System.setProperty("MAIN_CLASS", S3Configuration.class.getName());
1005+
System.setProperty("spring.cloud.function.definition", "outputS3Event");
1006+
FunctionInvoker invoker = new FunctionInvoker();
1007+
1008+
InputStream targetStream = new ByteArrayInputStream(this.s3Event.getBytes());
1009+
ByteArrayOutputStream output = new ByteArrayOutputStream();
1010+
invoker.handleRequest(targetStream, output, null);
1011+
assertThat(output.toByteArray()).isNotNull();
1012+
}
1013+
10021014
@Test
10031015
public void testS3Event() throws Exception {
10041016
System.setProperty("MAIN_CLASS", S3Configuration.class.getName());
@@ -1679,6 +1691,13 @@ public Function<Map<String, Object>, String> inputSNSEventAsMap() {
16791691
@EnableAutoConfiguration
16801692
@Configuration
16811693
public static class S3Configuration {
1694+
1695+
@Bean
1696+
public Function<S3Event, S3Event> outputS3Event() {
1697+
return v -> {
1698+
return v;
1699+
};
1700+
}
16821701
@Bean
16831702
public Function<String, String> echoString() {
16841703
return v -> v;

0 commit comments

Comments
 (0)