Java AWS Lambda Example with Serverless and Maven

Last Updated:  November 8, 2021 | Published: May 8, 2020

With this blog post, you'll learn how to use the Serverless framework to develop AWS Lambda functions using Java and Maven. To provide you with a realistic use case, we'll develop an AWS Lambda that will generate a thumbnail for each new image that we upload to an S3 bucket.

AWS Account Setup for Serverless

(If your AWS account is eligible for the free tier, you can mirror this setup in your own account free of cost.)

For deploying our Java function to AWS Lambda we'll use the Serverless framework. This framework simplifies the deployment of functions to different cloud providers (e.g. AWS Lambda, Azure Functions, etc.) with an abstraction layer. Alternative tools to get our Java function deployed to AWS Lambda are AWS SAM, CloudFormation, or the AWS CDK.

The Serverless framework takes care to create all required AWS resources for our AWS Lambda function. This includes the S3 Bucket for the Java code, IAM roles, and the Lambda function configuration. We don't have to fiddle around with long CloudFormation YAML templates at all.

We install the Serverless CLI via npm:

Next, we have to set up the AWS credentials for our AWS account. We can follow the instructions on their documentation for this and create a new IAM user in your AWS account called serverless-admin.

Once we have the access key and secret for this new user ready, we can store these credentials in a dedicated profile:

Maven Project Setup for AWS Lambda

Our Maven project is a plain Java 11 project with several AWS specific dependencies:

As we'll access images in an S3 bucket, we need the official AWS Java SDK for this. Unfortunately, we can't use v2 of the AWS SDK here already, as the aws-lambda-java-events right now only works with v1. This event dependency includes the S3Event class, that we can use to have typesafe access inside the lambda to react on. If you prefer to use the AWS SDK v2, you can either provide your own representation of the S3Event (e.g. copy it) or use a JSON representation of the incoming Lambda input.

Finally, the aws-lambda-java-core dependency contains the RequestHandler<I, O> we have to implement to create a Java-based Lambda function.

The JAXB dependency is optional, but without it, the AWS Lambda outputs a warning log message as since Java 11 JAXB is removed from the JDK.

As of now, AWS Lambda provides Java 8 and 11 runtimes, but we can also ship our own container image to run more recent Java code on AWS Lambda.

Furthermore, we have to create a Uber Jar and package all dependencies with the maven-shade-plugin.

With this setup, we'll create an 8 MB .jar file. As for each new AWS Lambda function deployment we have to upload this file to an S3 bucket (will be handled by the Serverless framework), we should try to keep the size of your .jar as small as possible.

Creating Image Thumbnails with Java and AWS Lambda

Writing an AWS Lambda function with Java requires implementing the RequestHandler<I, O> interface. This interface takes two parameters: one for the incoming input (I) of the Lambda function and one for the return type (aka. output O).

The input Java class can be any plain old Java object that maps to our input payload. AWS Lambda takes care of serializing the incoming payload using Jackson. The same is true for the return type of our AWS Lambda function. AWS Lambda deserializes our return type to JSON by default. If we don't want to use this default serialization behavior, we can implement the RequestStreamHandler interface instead.

As our Lambda function is triggered by S3 ObjectCreated events, we can use the S3Event (from aws-lambda-java-events) as the input type. The return type can be Void in this case, as we don't return anything and just process the uploaded image to create a thumbnail of it.

The incoming S3Event comes with information about which file was uploaded. We can extract this information and use the S3 Java client to get the image. AWS Lambda executes the Java function with the specified IAM role of the Lambda function, we don't have to provide any credentials to construct the client. Just ensure the IAM role has enough rights to perform the S3 operations.

Once the uploaded file is stored in a temporary file, we can perform the thumbnail generation with the help of BufferedImage and ImageIO. The thumbnail size is obtained from an environment variable we'll configure with Serverless in the next section.

Please note that this is a prototype-ish implementation of this thumbnail generation, there might be more elegant ways of doing it:

Once the image is processed, we'll store the thumbnail in S3 with the following file structure: thumbnails/100x100-nameOfImage.png.

Deploying the AWS Lambda with Serverless

As the final step, we'll configure Serverless to deploy our AWS Lambda function. For this, we'll create a serverless.yml file in the root of our project (next to our pom.xml).

First, we have to configure some information about the provider. Among other things, this includes the name of the cloud provider, the runtime, the region. Furthermore, you can specify the AWS profile you configured your credentials locally (otherwise it will use the default profile).

As the Lambda function needs access to the S3 bucket we'll use to upload images to, we have to also adjust the iamRoleStatements field and grant access to also the S3 deployment bucket which contains a ZIP file of our .jar :

Next, we have to tell Serverless where to find our build artifact and define the function:

This points to the .jar file and the handler attribute contains the fully qualified class name of our Java handler class. With the events attribute we specify the way our function is triggered. We limit this to include only the creation of objects in S3 with the uploads/ prefix and .png suffix e.g. uploads/myProfilePicture.png. While specifying the name of the S3 bucket, Serverless also ensures to create the bucket for us.

We can now deploy everything with serverless deploy -v. Make sure to build the Maven project with mvn package first.

Testing Time

Once the Lambda function is deployed, we can upload a .png file to the S3 bucket and should find the thumbnail shortly after:

Please note that the first Lambda execution is a cold start and might require more time.

The first run takes approx. 6 seconds for me, but all subsequent executions finish in 400 – 500ms.

To remove the AWS Lambda and all the supporting infrastructure that the Serverless framework created, make sure the S3 image bucket is empty and run:

For more Java AWS Lambda examples, consider the following blog posts:

The source code for this Java Lambda function using the Serverless framework and Maven is available on GitHub.

For a hands-on demonstration of using Java for AWS Lambda, consider enrolling in my (free) Going Serverless with Java course.

Have fun deploying Java functions to AWS Lambda using the Serverless framework,

Phil

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >