I’m working on some AWS lambdas to create an Alexa feature. As a self respecting software professional, I want to test al the software I write. However, this seems to be a rare practice when writing AWS functions.
This particular lambda should process events from a DynamoDB stream. Online, plenty of json
examples can be found for this event. However, the lambda extends
RequestHandler[DynamodbEvent, String]
and therefore has a function override def handleRequest(input: DynamodbEvent, context: Context): String
.
To be able to test this, I need an instance of DynamodbEvent
. Since this is quite a complex Pojo I would rather not create one manually, but just use the json
example.
Although the aws-java-sdk-core
library contains a com.amazonaws.util.json.Jackson
utility class, this class cannot deserialize the example into a
DynamodbEvent
instance. There are 2 main problems when deserializing the json:
To solve the first issue, Jackson has a, not so well, documented feature to add ‘mixIn’s. This allows the addition of extra interfaces to existing classes before deserializing. This interface must then define the methods which cause the problem. By adding the appropriate Jackson annotations, the problem can be solved.
interface RecordIgnoreDuplicateMethods {
@JsonIgnore // this overloaded method causes a problem deserializing json
public void setEventName(OperationType eventName);
@JsonProperty("eventName")
public void setEventName(String eventName);
}
To mixin the interface:
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(com.amazonaws.services.dynamodbv2.model.Record.class, RecordIgnoreDuplicateMethods.class);
The second problem can be solved by using a custom PropertyNamingStrategy
. First I thought this class is only used to determine the property name when
serializing a Pojo, but apparently it is also used when deserializing json into a Pojo.
The trick is to list all the property names which are translated wrong and provide the correct translation yourself.
public static class PropertyNamingFix extends PropertyNamingStrategy.PropertyNamingStrategyBase {
@Override
public String translate(String propertyName) {
switch(propertyName) {
case "eventID":
return "eventID";
case "eventVersion":
return "eventVersion";
case "eventSource":
return "eventSource";
case "awsRegion":
return "awsRegion";
case "dynamodb":
return "dynamodb";
case "eventSourceARN":
return "eventSourceARN";
default:
String first = propertyName.substring(0, 1);
String rest = propertyName.substring(1);
return first.toUpperCase() + rest;
}
}
}
Also add this to the mapper:
mapper.setPropertyNamingStrategy(new PropertyNamingFix());
And that’s it. Now, finally, a DynamodbEvent
instance can be created based on json and I can properly test and debug my lambda before publishing it to AWS.
See this gist for the complete solution.