DiversIT Europe
Previous Home Next Nov 1, 2017 Deserialising json into an AWS DynamodbEvent Tags: aws jackson java json lambda

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:

  • some Pojos have overloaded methods and Jackson cannot choose which method to use.
  • the json uses property names both with upper and lower case first letter. E.g. ‘Record’ and ‘eventID’.

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.