Shubha P
Shubha P

Reputation: 31

AWS Lambda function throws ClassNotFoundException

I have a Spring Boot demo project. I am trying to deploy them in AWS Lambda, but I get ClassNotFoundException even thought my jar that I upload contains of the necessary dependencies.

Here goes my code:

pom.xml

<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-core</artifactId>
        <version>1.2.1</version>
    </dependency>

    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-events</artifactId>
        <version>3.6.0</version>
    </dependency>

    <dependency>
        <groupId>com.amazonaws.serverless</groupId>
        <artifactId>aws-serverless-java-container-spring</artifactId>
        <version>[0.1,)</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Application Class

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        System.out.println("Welcome to demo project");
    }
}

Controller Class

@RestController
public class DemoController {

    @GetMapping(value="/getValue")
    public String getId() {
        return " Call from controller";
    }
}

LambdaHandler Class

public class DemoLambdaHandler implements RequestStreamHandler {

    public static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;

    static {
        try {
            handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(DemoApplication.class);
        } catch (ContainerInitializationException e) {
            e.printStackTrace();
            throw new RuntimeException("Container not initialized", e);
        }
    }

    @Override
    public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
        // TODO Auto-generated method stub
        handler.proxyStream(input, output, context);

    }
}

Not sure what I could be missing in this. Kindly help. Below is my inspected jar enter image description here

Upvotes: 2

Views: 5941

Answers (4)

Luis
Luis

Reputation: 31

I had the same issue, I fixed it marking Spring Boot as a dependency.

By default, Spring Boot plugin will pack your classes into "BOOT-INF/classes" directory, but AWS is looking for the handler class from the root directory so it can't find it.

You can check this by extracting your .jar file and seeing if your file is in:

BOOT-INF/classes/com/example/demo/handler/LambdaHandler.class

instead of:

com/example/demo/handler/LambdaHandler.class

To solve it, just mark your package as exec in your pom.xml file:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.1</version>
    <configuration>
        <classifier>exec</classifier>
    </configuration>
</plugin>

More info here: Spring Boot as a Dependency

Upvotes: 2

NaveenKrishnan01
NaveenKrishnan01

Reputation: 1

Please add these two dependencies in pomfile

1)aws-lambda-java-core

2)aws-lambda-java-events

This should fix it

Upvotes: -2

smac2020
smac2020

Reputation: 10734

Try building the project with Maven and ensure you have the required maven-shade-plugin in your POM so that the JAR that is built with the dependencies when you run mvn package. If you are missing this plugin, you will create a JAR that does not contain the dependencies and you will encounter ClassNotFoundException.

To learn how to build and deploy a Lambda function by using the Lambda runtime Java API, see this AWS tutorial. It will walk you step by step through the process of building Lambda functions that work:

https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javav2/usecases/creating_workflows_stepfunctions

This tutorial then uses the Lambda functions within Step Functions to create a workflow.

Lambda functions are created using the Lambda runtime Java API -- com.amazonaws.services.lambda.runtime.RequestHandler. Please do not use Spring BOOT APIs to create a Lambda function.

However, If you want to invoke a Lambda function from a Spring boot app and then for example display the result in a view, then you can use the Lambda Client Java API - which is software.amazon.awssdk.services.lambda.LambdaClient.

So in summary:

Upvotes: 0

Alappin
Alappin

Reputation: 684

Did you find a solution to this? I have been getting the same exact error.

What I can tell so far is that unlike other languages like nodejs, the docker image for java has the command specified like CMD [ "com.example.LambdaHandler::handleRequest" ], instead the nodejs one is CMD [ "app.handler" ]. The difference here is that the nodejs one specifies what the file is e.g. app.js with function called handler.

But the java one only has the class path without the ability to specify the path to the fat JAR file even when the jar file is located in "var/task". How would lambda know the JAR file name?

Upvotes: 2

Related Questions