AWS DynamoDB trigger using Lambda in JAVA
Asked Answered
S

6

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

Schlock answered 3/8, 2015 at 13:47 Comment(1)
Possible duplicate of Setup DynamoDB Trigger using LambdaDepolymerize
K
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.

Kirmess answered 29/12, 2015 at 7:26 Comment(3)
what is DynamodbEvent?Parasynthesis
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'Slagle
'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.Quantize
N
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.

Nakasuji answered 12/11, 2015 at 13:22 Comment(0)
C
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.

Creodont answered 23/8, 2015 at 20:48 Comment(0)
D
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;
    }

}
Decasyllabic answered 15/2, 2016 at 22:33 Comment(2)
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>Decasyllabic
It appears that RequestHandler is now deprecatedUnderfoot
L
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.

Letitialetizia answered 14/5, 2016 at 4:24 Comment(0)
H
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": "...")

Hierarchize answered 18/10, 2022 at 12:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.