AWS Developer Blog

Invoking AWS Lambda Functions from Java

by David Murray | on | in Java | Permalink | Comments |  Share

AWS Lambda makes it incredibly easy and cost-effective to run your code at arbitrary scale in the cloud. Simply write the handler code for your function and upload it to Lambda. The service takes care of hosting and scaling the function for you. And in case you somehow missed it, it now supports writing function handlers in Java!

Although many use cases for Lambda involve running code in response to triggers from other AWS services like Amazon S3 or Amazon Cognito, you can also invoke Lambda functions directly, making them an easy and elastically scalable way to decompose an application into reusable microservices. In this post, we’ll assume we’ve got a Lambda function named “CountCats” that accepts an S3 bucket and key for an image, analyzes the image to count the number of cats the image contains, and returns that count to the caller. An example request to this service might look like:

{
  "bucket": "pictures-of-cats",
  "key": "three-cool-cats.jpg"
}

And an example response might look like:

{
  "count": 3
}

To invoke this function from Java code, we’ll first define POJOs representing the input and output JSON:

public class CountCatsInput {

  private String bucketName;
  private String key;

  public String getBucketName() { return bucketName; }
  public void setBucketName(String value) { bucketName = value; }

  public String getKey() { return key; }
  public void setKey(String value) { key = value; }
}

public class CountCatsOutput {

  private int count;

  public int getCount() { return count; }
  public void setCount(int value) { count = value; }
}

Next we’ll define an interface representing our microservice, and annotate it with the name of the Lambda function to invoke when it’s called:

import com.amazonaws.services.lambda.invoke.LambdaFunction;

public interface CatService {
  @LambdaFunction(functionName="CountCats")
  CountCatsOutput countCats(CountCatsInput input);
}

We can then use the LambdaInvokerFactory to create an implementation of this interface that will make calls to our service running on Lambda (note that providing a lambdaClient is optional, if one is not provided a default client will be used):

import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.invoke.LambdaInvokerFactory;

final CatService catService = LambdaInvokerFactory.builder()
 .lambdaClient(AWSLambdaClientBuilder.defaultClient())
 .build(CatService.class);

Finally, we invoke our service using this proxy object:

CountCatsInput input = new CountCatsInput();
input.setBucketName("pictures-of-cats");
input.setKey("three-cute-cats");

int cats = catService.countCats(input).getCount();

When called, the input POJO is serialized to JSON and sent to your Lambda function; the function’s result is transparently deserialized back into your output POJO. Details like authentication, timeouts, and retries in case of transient network issues are handled by the underlying AWSLambdaClient.

Are you using Lambda to host a microservice and calling it from Java code? Let us know how it’s going in the comments or over on our GitHub repository!