Skip to content

Commit b9317d0

Browse files
sdelamotimyates
andauthored
fix: CustomPojoSerializer only for Serde (#1916)
* fix: CustomPojoSerializer only for Serde Close #1914 This PR remove the `CustomPojoSerializer` when using `JacksonDatabind`. Jackson’s `ObjectMapper ` creation requires customization which I don’t think it make sense to replicate in our `CustomPojoSerializer`. https://github.com/aws/aws-lambda-java-libs/blob/main/aws-lambda-java-serialization/src/main/java/com/amazonaws/services/lambda/runtime/serialization/factories/JacksonFactory.java#L57-L93 * Cleanup imports and use generics * Update src/main/docs/guide/lambda/eventsLambdaSerde.adoc Co-authored-by: Tim Yates <[email protected]> --------- Co-authored-by: Tim Yates <[email protected]>
1 parent e6e094c commit b9317d0

File tree

16 files changed

+166
-30
lines changed

16 files changed

+166
-30
lines changed

gradle/libs.versions.toml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ managed-aws-java-sdk-v2 = '2.20.162'
2929
managed-aws-lambda = '1.2.3'
3030
managed-aws-lambda-events = '3.11.3'
3131
managed-aws-lambda-java-serialization = '1.1.2'
32+
aws-lambda-java-runtime-interface-client = '2.4.1'
3233

3334
managed-aws-serverless-core = '1.9.3'
3435
micronaut-starter = "3.9.2"
@@ -109,6 +110,7 @@ managed-aws-java-sdk-core = { module = 'com.amazonaws:aws-java-sdk-core', versio
109110
managed-aws-lambda-core = { module = 'com.amazonaws:aws-lambda-java-core', version.ref = 'managed-aws-lambda'}
110111
managed-aws-lambda-events = { module = 'com.amazonaws:aws-lambda-java-events', version.ref = 'managed-aws-lambda-events' }
111112
managed-aws-lambda-java-serialization = { module = 'com.amazonaws:aws-lambda-java-serialization', version.ref = 'managed-aws-lambda-java-serialization' }
113+
aws-lambda-java-runtimeinterfaceclient = { module = 'com.amazonaws:aws-lambda-java-runtime-interface-client', version.ref = 'aws-lambda-java-runtime-interface-client' }
112114

113115
managed-awssdk-secretsmanager = { module = 'software.amazon.awssdk:secretsmanager', version.ref = 'managed-aws-java-sdk-v2' }
114116
managed-jcl-over-slf4j = { module = 'org.slf4j:jcl-over-slf4j', version.ref = 'slf4j' }
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
`micronaut-function-aws` provides an implementation of `com.amazonaws.services.lambda.runtime.CustomPojoSerializer` which is loaded via SPI. This `CustomPojoSerialization` avoids your Micronaut function to pay a double hit on performances when using a serialization library inside the Lambda function.
1+
You need to add a dependency to Micronaut Jackson Databind:
22

3-
You need to add a dependency to either https://micronaut-projects.github.io/micronaut-serialization/latest/guide[Micronaut Serialization]
4-
5-
dependency:micronaut-serde-jackson[groupId="io.micronaut.serde"]
3+
dependency:micronaut-jackson-databind[groupId="io.micronaut"]
64

7-
or to Micronaut Jackson Databind:
5+
or a dependency to https://micronaut-projects.github.io/micronaut-serialization/latest/guide[Micronaut Serialization]
86

9-
dependency:micronaut-jackson-databind[groupId="io.micronaut"]
7+
dependency:micronaut-serde-jackson[groupId="io.micronaut.serde"]
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
If you want to use https://micronaut-projects.github.io/micronaut-serialization/latest/guide/[Micronaut Serialization] with https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events[AWS Lambda Java Events] add the following dependency:
22

33
dependency:micronaut-aws-lambda-events-serde[groupId="io.micronaut.aws"]
4+
5+
`micronaut-aws-lambda-events-serde` provides an implementation of `com.amazonaws.services.lambda.runtime.CustomPojoSerializer` which is loaded via SPI.
6+
This `CustomPojoSerialization` avoids your Micronaut function paying a double hit on performance when using a serialization library inside the Lambda function.

test-suite-aws-lambda-events-jacksondatabind/src/test/java/io/micronaut/aws/lambda/events/jacksondatabind/AwsLambdaEventsJacksonDatabindSuite.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import org.junit.platform.suite.api.SuiteDisplayName;
66

77
@Suite
8-
@SelectPackages("io.micronaut.aws.lambda.events.tests")
8+
@SelectPackages({
9+
"io.micronaut.aws.lambda.events.tests",
10+
"io.micronaut.aws.lambda.events.jacksondatabind.tests"
11+
})
912
@SuiteDisplayName("AWS Lambda Events TCK for JacksonDatabind")
1013
public class AwsLambdaEventsJacksonDatabindSuite {
1114
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.micronaut.aws.lambda.events.jacksondatabind.tests;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static io.micronaut.aws.lambda.events.tests.CustomPojoSerializerUtils.loadSerializer;
6+
import static org.junit.jupiter.api.Assertions.assertNull;
7+
8+
class NoCustomPojoSerializerForJacksonDatabindTest {
9+
@Test
10+
void noCustomPojoSerializerForJacksonDatabindTest() {
11+
assertNull(loadSerializer());
12+
}
13+
}

test-suite-aws-lambda-events-serde/src/test/java/io/micronaut/aws/lambda/events/AwsLambdaEventsSerdeSuite.java

-11
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.micronaut.aws.lambda.events.serde;
2+
3+
import org.junit.platform.suite.api.ExcludeClassNamePatterns;
4+
import org.junit.platform.suite.api.SelectPackages;
5+
import org.junit.platform.suite.api.Suite;
6+
import org.junit.platform.suite.api.SuiteDisplayName;
7+
8+
@Suite
9+
@ExcludeClassNamePatterns(
10+
// Error decoding property [Map messageAttributes] of type [class com.amazonaws.services.lambda.runtime.events.SQSEvent$SQSMessage]: Error decoding property [ByteBuffer binaryValue] of type [class com.amazonaws.services.lambda.runtime.events.SQSEvent$MessageAttribute]
11+
"io.micronaut.aws.lambda.events.tests.SqsHandlerTest"
12+
)
13+
@SelectPackages({
14+
"io.micronaut.aws.lambda.events.tests",
15+
"io.micronaut.aws.lambda.events.serde.tests"
16+
})
17+
@SuiteDisplayName("AWS Lambda Events TCK for Serde")
18+
public class AwsLambdaEventsSerdeSuite {
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.micronaut.aws.lambda.events.serde.tests;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static io.micronaut.aws.lambda.events.tests.CustomPojoSerializerUtils.loadSerializer;
6+
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
8+
class CustomPojoSerializerForSerdeTest {
9+
@Test
10+
void customPojoSerializerForSerdeTest() {
11+
assertNotNull(loadSerializer());
12+
}
13+
}

test-suite-aws-lambda-events/build.gradle.kts

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ plugins {
22
id("java-library")
33
}
44
dependencies {
5-
implementation(libs.managed.aws.lambda.events)
5+
api(libs.aws.lambda.java.runtimeinterfaceclient)
6+
api(libs.managed.aws.lambda.events)
67
implementation(mnTest.micronaut.test.junit5)
78
implementation(projects.micronautFunctionAws)
89
}

test-suite-aws-lambda-events/src/main/java/io/micronaut/aws/lambda/events/tests/ApiGatewayV2EventTest.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22

33
import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;
44
import io.micronaut.aws.lambda.events.FileUtils;
5-
import io.micronaut.function.aws.JsonMapperCustomPojoSerializer;
65
import org.junit.jupiter.api.Test;
76

87
import java.io.IOException;
98

109
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
1110
import static org.junit.jupiter.api.Assertions.assertEquals;
1211
import static org.junit.jupiter.api.Assertions.assertFalse;
13-
import static org.junit.jupiter.api.Assertions.assertNotNull;
1412

1513
class ApiGatewayV2EventTest {
1614

@@ -47,10 +45,8 @@ public static void expectedEvent(APIGatewayV2HTTPEvent event) {
4745

4846
@Test
4947
void testDeserializationOfAPIGatewayV2HttpEvent() throws IOException {
50-
JsonMapperCustomPojoSerializer serializer = new JsonMapperCustomPojoSerializer();
5148
String json = FileUtils.text(this.getClass().getClassLoader(), "apiGatewayV2HTTPEvent.json").orElse(null);
52-
assertNotNull(json);
53-
APIGatewayV2HTTPEvent event = assertDoesNotThrow(() -> serializer.fromJson(json, APIGatewayV2HTTPEvent.class));
49+
APIGatewayV2HTTPEvent event = assertDoesNotThrow(() -> CustomPojoSerializerUtils.serializeFromJson(json, APIGatewayV2HTTPEvent.class));
5450
expectedEvent(event);
5551
}
5652
}

test-suite-aws-lambda-events/src/main/java/io/micronaut/aws/lambda/events/tests/ApplicationLoadBalancerRequestEventTest.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
44
import io.micronaut.aws.lambda.events.FileUtils;
5-
import io.micronaut.function.aws.JsonMapperCustomPojoSerializer;
65
import org.junit.jupiter.api.Test;
76

87
import java.io.IOException;
@@ -18,10 +17,9 @@ public class ApplicationLoadBalancerRequestEventTest {
1817
@Test
1918
@SuppressWarnings("java:S1313") // IP usage is safe here
2019
void testDeserializationOfApplicationLoadBalancerRequestEvent() throws IOException {
21-
JsonMapperCustomPojoSerializer serializer = new JsonMapperCustomPojoSerializer();
2220
String json = FileUtils.text(this.getClass().getClassLoader(), "albRequest.json").orElse(null);
2321
assertNotNull(json);
24-
ApplicationLoadBalancerRequestEvent event = assertDoesNotThrow(() -> serializer.fromJson(json, ApplicationLoadBalancerRequestEvent.class));
22+
ApplicationLoadBalancerRequestEvent event = assertDoesNotThrow(() -> CustomPojoSerializerUtils.serializeFromJson(json, ApplicationLoadBalancerRequestEvent.class));
2523
assertEquals("arn:aws:elasticloadbalancing:us-east-1:646307737039:targetgroup/fubar-dev-tg/97533b9b279f7d7f", event.getRequestContext().getElb().getTargetGroupArn());
2624
assertEquals("GET", event.getHttpMethod());
2725
assertEquals("/", event.getPath());

test-suite-aws-lambda-events/src/main/java/io/micronaut/aws/lambda/events/tests/ApplicationLoadBalancerResponseEventTest.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerResponseEvent;
44
import io.micronaut.aws.lambda.events.FileUtils;
5-
import io.micronaut.function.aws.JsonMapperCustomPojoSerializer;
65
import org.junit.jupiter.api.Test;
76

87
import java.io.IOException;
@@ -18,10 +17,9 @@ public class ApplicationLoadBalancerResponseEventTest {
1817

1918
@Test
2019
void testDeserializationOfApplicationLoadBalancerResponseEvent() throws IOException {
21-
JsonMapperCustomPojoSerializer serializer = new JsonMapperCustomPojoSerializer();
2220
String json = FileUtils.text(this.getClass().getClassLoader(), "albResponse.json").orElse(null);
2321
assertNotNull(json);
24-
ApplicationLoadBalancerResponseEvent event = assertDoesNotThrow(() -> serializer.fromJson(json, ApplicationLoadBalancerResponseEvent.class));
22+
ApplicationLoadBalancerResponseEvent event = assertDoesNotThrow(() -> CustomPojoSerializerUtils.serializeFromJson(json, ApplicationLoadBalancerResponseEvent.class));
2523
assertEquals(200, event.getStatusCode());
2624
assertNull(event.getStatusDescription());
2725
assertFalse(event.getIsBase64Encoded());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.micronaut.aws.lambda.events.tests;
2+
3+
import com.amazonaws.services.lambda.runtime.CustomPojoSerializer;
4+
import com.amazonaws.services.lambda.runtime.serialization.PojoSerializer;
5+
import com.amazonaws.services.lambda.runtime.serialization.events.LambdaEventSerializers;
6+
7+
import java.util.Iterator;
8+
import java.util.ServiceLoader;
9+
10+
public final class CustomPojoSerializerUtils {
11+
12+
private CustomPojoSerializerUtils() {
13+
}
14+
15+
public static CustomPojoSerializer loadSerializer() {
16+
17+
ServiceLoader<CustomPojoSerializer> loader = ServiceLoader.load(CustomPojoSerializer.class);
18+
Iterator<CustomPojoSerializer> serializers = loader.iterator();
19+
20+
if (!serializers.hasNext()) {
21+
return null;
22+
}
23+
24+
return serializers.next();
25+
}
26+
27+
public static <T> PojoSerializer<T> loadSerializer(Class<T> eventClass) {
28+
return LambdaEventSerializers.serializerFor(eventClass, CustomPojoSerializerUtils.class.getClassLoader());
29+
}
30+
31+
public static <T> T serializeFromJson(String input, Class<T> eventClass) {
32+
CustomPojoSerializer customPojoSerializer = loadSerializer();
33+
if (customPojoSerializer != null) {
34+
return customPojoSerializer.fromJson(input, eventClass);
35+
}
36+
37+
PojoSerializer<T> pojoSerializer = loadSerializer(eventClass);
38+
return pojoSerializer.fromJson(input);
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.micronaut.aws.lambda.events.tests;
2+
3+
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
4+
import io.micronaut.aws.lambda.events.FileUtils;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.io.IOException;
8+
9+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
import static org.junit.jupiter.api.Assertions.assertNotNull;
12+
13+
public class SqsHandlerTest {
14+
@Test
15+
void testDeserializationOfApplicationLoadBalancerRequestEvent() throws IOException {
16+
String json = FileUtils.text(this.getClass().getClassLoader(), "sqs-event.json").orElse(null);
17+
assertNotNull(json);
18+
SQSEvent event = assertDoesNotThrow(() -> CustomPojoSerializerUtils.serializeFromJson(json, SQSEvent.class));
19+
assertNotNull(event);
20+
assertNotNull(event.getRecords());
21+
assertEquals(1, event.getRecords().size());
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"Records": [
3+
{
4+
"messageId" : "MessageID_1",
5+
"receiptHandle" : "MessageReceiptHandle",
6+
"body" : "Message Body",
7+
"md5OfBody" : "fce0ea8dd236ccb3ed9b37dae260836f",
8+
"md5OfMessageAttributes" : "582c92c5c5b6ac403040a4f3ab3115c9",
9+
"eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:SQSQueue",
10+
"eventSource": "aws:sqs",
11+
"awsRegion": "us-west-2",
12+
"attributes" : {
13+
"ApproximateReceiveCount" : "2",
14+
"SentTimestamp" : "1520621625029",
15+
"SenderId" : "AROAIWPX5BD2BHG722MW4:sender",
16+
"ApproximateFirstReceiveTimestamp" : "1520621634884"
17+
},
18+
"messageAttributes" : {
19+
"Attribute3" : {
20+
"binaryValue" : "MTEwMA==",
21+
"stringListValues" : ["abc", "123"],
22+
"binaryListValues" : ["MA==", "MQ==", "MA=="],
23+
"dataType" : "Binary"
24+
},
25+
"Attribute2" : {
26+
"stringValue" : "123",
27+
"stringListValues" : [ ],
28+
"binaryListValues" : ["MQ==", "MA=="],
29+
"dataType" : "Number"
30+
},
31+
"Attribute1" : {
32+
"stringValue" : "AttributeValue1",
33+
"stringListValues" : [ ],
34+
"binaryListValues" : [ ],
35+
"dataType" : "String"
36+
}
37+
}
38+
}
39+
]
40+
}

0 commit comments

Comments
 (0)