I wrote a Lambda function in Java and deployed it with SAM

Introduction

So far, I have made AWS Lambda mainly in Python, sometimes Node.js, but for a change I investigated how to develop in Java, so I will summarize it.

This time, I built the source code of the Lambda function written in Java with Gradle and deployed it with AWS SAM. The AWS Toolkit for Eclipse (https://docs.aws.amazon.com/ja_jp/toolkit-for-eclipse/v1/user-guide/welcome.html) is also provided for development in Eclipse, I usually develop with Vim and deploy with CLI, so I will match that.

Verification environment

Key points for developing Lambda with Java

~~ Runtime is Java 8 only ~~ Runtime is Java 8 and Java 11 (changed on November 19, 2019)

~~ As you can see in the official documentation below, the only Java runtime provided is Java 8 ( JDK 8). If you use any other version, you will have to wait until it is supported or use a custom runtime. ~~

Java 11 was added on November 19, 2019, and the runtime can now be selected between Java 8 (JDK 8) and Java 11 (JDK 11).

Building Lambda Functions with Java-AWS Lambda

Deploy as a zip or jar file

Package and deploy an application written in Java in a zip file or standalone jar.

The official documentation shows how to deploy to a standalone jar using Maven and a zip file using Gradle. This time, I tried the method of packaging and deploying to a zip file with Gradle.

Java AWS Lambda Deployment Package-AWS Lambda

There are three ways to receive and return handler function requests

There are multiple methods for receiving the request of the handler function and returning the response as follows.

  1. Java simple type
  2. POJO (Plain Old Java Object) type
  3. Stream type

How to write the handler function is different for each. In other words, there are three ways to write a handler function.

It seems that it is used properly from the viewpoint of what kind of data is sent, rather than how to decide "If you use this event trigger, this type". There seems to be no such thing as this in this situation, so it is important to consider which method to use when actually developing a Lambda function in Java.

This time, we adopted the "POJO type".

Handler I / O Type (Java) --AWS Lambda

What I made this time

I've created a simple web application that uses ʻAPI Gateway` as a trigger for a Lambda function. It's a simple API that just sends a POST request and returns "Hello".

Sample code

I put the created code here. https://github.com/mmclsntr/awslambda-javagradle

Project structure

.
├── build/
│   ├── distributions/
│   │   └── awslambda-javagradle.zip   #Deploy package generated by build
│   └── ...
├── build.gradle                    #Gradle build configuration file
├── src/main/java/awslambda/javagradle
│   ├── Greeting.java            #The core part of the app
│   ├── Handler.java             #Store Lambda handler function
│   └── Response.java            #Format Lambda response
└── template.yml                    #CloudFormation template file
└── Other files for Gradle

coding

Handler class

Handler.java


package awslambda.javagradle;

import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class Handler implements RequestHandler<Map<String, Object>, Response> {

	private static final Logger LOG = Logger.getLogger(Handler.class.getName());

	@Override
	public Response handleRequest(Map<String, Object> input, Context context) {
		LOG.info("received: " + input);
        LOG.setLevel(Level.INFO);

        Greeting greetingBody = new Greeting("Hello");

		return Response.builder()
				.setStatusCode(200)
				.setObjectBody(greetingBody)
				.build();
	}
}

Response class

Response.java


package awslambda.javagradle;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
import org.apache.log4j.Logger;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Response {

	private final int statusCode;
	private final String body;
	private final Map<String, String> headers;
	private final boolean isBase64Encoded;

	public Response(int statusCode, String body, Map<String, String> headers, boolean isBase64Encoded) {
		this.statusCode = statusCode;
		this.body = body;
		this.headers = headers;
		this.isBase64Encoded = isBase64Encoded;
	}
	...

}

Greeting class

Create a super simple application that returns Hello as a sample.

Greeting.java


package awslambda.javagradle;

public class Greeting {
    private String greetings;

    public Greeting(String greetings) {
        this.greetings = greetings;
    }
    public String getGreetings() {
        return greetings;
    }

    public void setGreetings(String greetings) {
        this.greetings = greetings;
    }
}

CloudFormation template

template.yml


AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
    AWS Lambda Java with Gradle

Globals:
    Function:
        Timeout: 20

Resources:
  PostGreetingFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/distributions/awslambda-javagradle.zip
      Handler: awslambda.javagradle.Handler::handleRequest
      Runtime: java8
      Events:
        GetOrder:
          Type: Api
          Properties:
            Path: /
            Method: post

Outputs:
    ApiEndpoint:
      Description: "API Gateway endpoint URL for Prod stage"
      Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

    PostGreetingFunction:
      Description: "PostGreeting Lambda Function ARN"
      Value: !GetAtt PostGreetingFunction.Arn

Deploy

Build configuration file creation

build.gradle


apply plugin: 'java'

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile (
        'com.amazonaws:aws-lambda-java-core:1.1.0',
        'com.amazonaws:aws-lambda-java-log4j:1.0.0',
        'com.amazonaws:aws-lambda-java-events:1.1.0',
        'com.fasterxml.jackson.core:jackson-core:2.8.5',
        'com.fasterxml.jackson.core:jackson-databind:2.8.5',
        'com.fasterxml.jackson.core:jackson-annotations:2.8.5'
    )
}

// Task for building the zip file for upload
task buildZip(type: Zip) {
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtime
    }
}

build.dependsOn buildZip

Build

Build with the Gradle command.

gradle build

Deploy with AWS SAM

Create deployment destination S3 bucket

aws s3 mb s3://<Deploy to S3 bucket> --aws-profile=<AWS profile>

package

With sam package, upload the executable file to the S3 bucket created above & generate a template file for deployment.

sam package \
--s3-bucket <Deploy destination S3 bucket name> \
--s3-prefix <Deployment destination S3 folder name(Prefix)※Any> \
--output-template-file output.yml \
--profile <AWS profile>

As an output, a ʻoutput.yml` file is created.

Deploy

Deploy Lambda and API Gateway with sam deploy.

sam deploy \
--template-file output.yml \
--stack-name awslambda-javagradle-greeting \
--capabilities CAPABILITY_IAM \
--profile <AWS profile>

Verification

Now that we have a Lambda function and API Gateway on AWS, let's throw a POST request to the endpoint.

request


curl -X POST https://xxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/

response


{"greetings":"Hello"}

Impressions

I myself don't usually use Java, so it took me a while, but I have the impression that it was easy to make. Of course, the amount of code is larger than writing in a scripting language such as Python, but it is attractive to be able to do rigorous serverless development.

I couldn't grasp the specific specifications for writing in Java, such as multiple types of handler function writing, just this time. When actually using it, I would like to design it in detail while considering that area.

Also, as rumored, the initial startup is slow (about 5 seconds until it responds). Reference: https://cero-t.hatenadiary.jp/entry/20160106/1452090214

Summary

I was able to grasp the characteristics and coding sense of developing Lambda functions using Java. If you're migrating from a Servlet, I think it will require a fairly large-scale refurbishment, but I have the impression that it can be used as a substitute.

I'm a little worried about the support there, whether the runtime is just Java 8 as it is. .. I used API Gateway as a trigger, but I would like to try other services as well.

reference

https://qiita.com/kamata1729/items/8d88ea10dd3bb61fa6cc https://qiita.com/riversun/items/7fcc06617b469aed8f27

Recommended Posts

I wrote a Lambda function in Java and deployed it with SAM
I want to make a function with kotlin and java!
I wrote a route search program in TDD and refactored it
I wrote a primality test program in Java
I want to ForEach an array with a Lambda expression in Java
I wrote a prime factorization program in Java
Write a class in Kotlin and call it in Java
I tried to make a login function in Java
I tried to create a shopping site administrator function / screen with Java and Spring
Assign a Java8 lambda expression to a variable and reuse it
I want to make a list with kotlin and java!
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I created a PDF in Java.
I wrote Goldbach's theorem in java
A memo when I tried "Talking about writing a Java application in Eclipse and publishing it in Kubernetes with a Liberty container (Part 1)"
I can't create a Java class with a specific name in IntelliJ
I made a Ruby container image and moved the Lambda function
I wrote a Stalin sort that feels like a mess in Java
Graph the sensor information of Raspberry Pi in Java and check it with a web browser
[Java] for Each and sorted in Lambda
Split a string with ". (Dot)" in Java
Working with huge JSON in Java Lambda
What I don't like when using interface of a function with default arguments in Kotlin from Java
I made a primality test program in Java
I received the data of the journey (diary application) in Java and visualized it # 001
Read a string in a PDF file with Java
Create a CSR with extended information in Java
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (Javassist second decoction)
I wanted to make (a == 1 && a == 2 && a == 3) true in Java
How to ZIP a JAVA CSV file and manage it in a Byte array
Prepare a scraping environment with Docker and Java
Let's create a TODO application in Java 2 I want to create a template with Spring Initializr and make a Hello world
Encrypt / decrypt with AES256 in PHP and Java
I tried to break a block with java (1)
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (black magic edition)
Create a Java (Gradle) project with VS Code and develop it on a Docker container
[Java] Precautions when referencing a reference type in a parent class and instantiating it in a child class
Create a Java (Maven) project with VS Code and develop it on a Docker container
I made a function to register images with API in Spring Framework. Part 1 (API edition)
I made a simple calculation problem game in Java
I tried Mastodon's Toot and Streaming API in Java
[Ruby] I made a crawler with anemone and nokogiri.
I tried to create a Clova skill in Java
Quickly implement a singleton with an enum in Java
I dealt with Azure Functions not working in Java
I want to define a function in Rails Console
I tried OCR processing a PDF file with Java
What I learned when building a server in Java
Output true with if (a == 1 && a == 2 && a == 3) in Java (Invisible Identifier)
How to convert A to a and a to A using AND and OR in Java
I wrote a test with Spring Boot + JUnit 5 now
[Java] A technique for writing constructors, getters, and setters in one shot with IntelliJ IDEA.
Until you build a project described in scala with Maven and execute it with the scala command.
I made a function to register images with API in Spring Framework. Part 2 (Client Edition)
I made a program in Java that solves the traveling salesman problem with a genetic algorithm
Store in Java 2D map and turn with for statement
I wrote a CRUD test with SpringBoot + MyBatis + DBUnit (Part 1)
I tried to create a java8 development environment with Chocolatey
Implement Thread in Java and try using anonymous class, lambda
Memorandum No.4 "Get a character string and decorate it" [Java]
I tried to modernize a Java EE application with OpenShift.