8

I am trying to trigger an AWS lambda function written in Java, on dynamodb stream events. Amazon has a guide for the same, using NodeJS here http://docs.aws.amazon.com/lambda/latest/dg/wt-ddb-create-test-function.html

The testing input for NodeJS (from the above link) looks like an SNS event, so I tried to use the corresponding SNSEvent class in Java as an input to my handler method.

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord;
import java.util.List;

public class RecomFunction {

    public void handler(SNSEvent event, Context context) {

        LambdaLogger logger = context.getLogger();

        List<SNSRecord> records = event.getRecords();

        if (records != null) {
            for (SNSRecord record : records) {
                if (record != null) {
                    logger.log("SNS record: " + record.getSNS().getMessage());
                }
            }
        }
    }

}

Unfortunately, record.getSNS() returns NULL resulting to a NullPointer exception

There is a related question, however a specific answer was not given: Setup DynamoDB Trigger using Lambda

1

6 Answers 6

13

This code worked for me. You can use it to receive and process DynamoDB events in a Lambda function -

public class Handler implements RequestHandler<DynamodbEvent, Void> {

    @Override
    public Void handleRequest(DynamodbEvent dynamodbEvent, Context context) {

        for (DynamodbStreamRecord record : dynamodbEvent.getRecords()) {

            if (record == null) {
                continue;
            }

            // Your code here
        }

        return null;
    }
}

Similarly, you can use SNSEvent and SNSRecord to handle Amazon SNS events.

Sign up to request clarification or add additional context in comments.

3 Comments

what is DynamodbEvent?
This worked for me very well. It remains to say that DynamodbEvent is part of following gradle dependency: compile group: 'com.amazonaws', name: 'aws-lambda-java-events', version: '2.1.0'
'com.amazonaws:aws-lambda-java-core:1.2.1' 'com.amazonaws:aws-lambda-java-events:2.2.8' 'com.amazonaws:aws-lambda-java-events-sdk-transformer:1.0.0' 'com.amazonaws:aws-lambda-java-log4j:1.0.1' 'com.amazonaws:aws-lambda-java-log4j2:1.2.0' see github.com/aws/aws-lambda-java-libs DynamodbEvent is defined there.
3

This worked for me - case DynamoDB stream events:

import com.amazonaws.services.lambda.runtime.RequestHandler;
...

public class DynamoStreamHandler implements RequestHandler<Object, Void> {
    @Override
    public Void handleRequest(Object o, Context context) {

        LinkedHashMap lhm = (LinkedHashMap) o;
        ...etc.
    }
}

It seems they use a customized JSON mapper which utilizes Map and List objects. It's quite straightforward (but tedious) to verify this for other event types by testing and print-outing logs. (sigh)

EDIT: If ~5 MB overhead is ok, you can use DynamodbEvent.DynamodbStreamRecord provided by aws-lambda-java-events library v1.1.0 as described in AWS Lambda Walkthrough 3: Process Amazon DynamoDB Events (Java) in AWS Lambda Documentation.

Comments

2

Create a handler that takes an InputStream, read in the contents of the InputStream (which is just JSON) and then deserialize it to get the data that you need.

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.amazonaws.services.lambda.runtime.Context; 

public class MyHandler {    
    public void handler(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {           
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int letter;        
        while((letter = inputStream.read()) != -1)
        {
            baos.write(letter);                     
        }        

        //Send the contents of baos to a JSON deserializer ...          
    }      
}

It's a bit cumbersome, but as far as I'm aware AWS doesn't currently provide a higher level Java lambda interface for consuming DynamoDB Streams. I have a full blown example here with details on how I deserialized the stream of JSON to get Java objects for the data.

Comments

0

Your code caused the following exception in CloudWatch log,

Class does not implement an appropriate handler interface....

Once I changed the code to the following, I can get the SNS message just fine.

public class RecomFunction implements RequestHandler<SNSEvent, Void> {

    public Void handleRequest(SNSEvent event, Context context) {

        ...
        return null;
    }

}

2 Comments

One more thing, you will need to include aws-lambda-java-events to your shaded JAR. aws-lambda-java-core, however, can be set to <scope>provided</scope>
It appears that RequestHandler is now deprecated
0

To obtain the deserialized objects from event handler : 1) In the handler get json from input stream using something like this :

private String getJsonFrom(InputStream stream) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int letter;
    while ((letter = stream.read()) != -1)
        baos.write(letter);

    return new String(baos.toByteArray());
}

2) Then create a specific deserializer derialize the object from json. 'NewImage' in case of DynamoDB event. One example here.

Comments

0

none of the above answers helped me. Using Object I have got the content, but thats not enough. To make DynamodbEvent work I had to send proper event JSON event to my lambda. Using the AWS test JSON content there are couple of attributes which are missing. While attaching the DynamoDB with streams to the Lambda and doing some changes there, then I will get proper JSON content and DynamodbEvent will work in the RequestHandler. So putting tight attributes in the JSON event makes it work (like: "awsRegion": "us-west-2", "eventName": "INSERT", "eventSourceARN": "...", "eventSource": "...")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.