DigVen
DigVen

Reputation: 63

Quarkus - Dependencies not included in uber jar - JVM mode

I have the a quarkus project created with "amazon-lambda, resteasy, jackson. and gson" libraries. I have a StreamLambdaHandler implementing the RequestStreamHandler. I am running the application in JVM mode.

I have the below property added in application.properties:

quarkus.package.uber-jar=true

I am using the thin jar named code-with-quarkus-1-runner.jar.

Sending a JSON POST request from API gateway is giving below exception. Please let me know what could be the issue.

Error loading class org.test.StreamLambdaHandler: com/google/gson/JsonElement:
java.lang.NoClassDefFoundError
java.lang.NoClassDefFoundError: com/google/gson/JsonElement
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.google.gson.JsonElement. Current
classpath: file:/var/task/

Expected behavior the gson libraries should have been copied in the uber jar and should not have thrown any exceptions

Actual behavior: Sending a JSON POST request from API gateway is giving below exception. Please let me know what could be the issue.

Error loading class org.test.StreamLambdaHandler: com/google/gson/JsonElement:
java.lang.NoClassDefFoundError
java.lang.NoClassDefFoundError: com/google/gson/JsonElement
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.google.gson.JsonElement
Current classpath: file:/var/task/

Below is my pom.xml file:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.acme</groupId>
  <artifactId>code-with-quarkus</artifactId>
  <version>1</version>
  <properties>
    <compiler-plugin.version>3.8.1</compiler-plugin.version>
    <maven.compiler.parameters>true</maven.compiler.parameters>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
    <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
    <quarkus.platform.version>2.0.2.Final</quarkus.platform.version>
    <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
    <quarkus.package.type>uber-jar</quarkus.package.type>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-amazon-lambda</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus.platform.version}</version>
        <extensions>true</extensions>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
              <goal>generate-code</goal>
              <goal>generate-code-tests</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compiler-plugin.version}</version>
        <configuration>
          <parameters>${maven.compiler.parameters}</parameters>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <configuration>
          <systemPropertyVariables>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <maven.home>${maven.home}</maven.home>
          </systemPropertyVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>native</id>
      <activation>
        <property>
          <name>native</name>
        </property>
      </activation>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${surefire-plugin.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>integration-test</goal>
                  <goal>verify</goal>
                </goals>
                <configuration>
                  <systemPropertyVariables>
                    <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                    <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                    <maven.home>${maven.home}</maven.home>
                  </systemPropertyVariables>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
      <properties>
        <quarkus.package.type>native</quarkus.package.type>
      </properties>
    </profile>
  </profiles>
</project>

Also, please find below for the RequestStreamHandler class code:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.google.gson.JsonObject;

public class StreamLambdaHandler implements RequestStreamHandler {
    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        JsonObject responseJson = new JsonObject();
        JsonObject responseBody = new JsonObject();
        responseBody.addProperty("message", "New item created");
        OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
        writer.write(responseJson.toString());
        writer.close();
    }
}

Upvotes: 1

Views: 5394

Answers (3)

DigVen
DigVen

Reputation: 63

The issue turned out to be with the way Quarkus is building the fat/uber jar when quarkus-amazon-lambda dependency is added. With this dependency added, fat jar is not created even if we explicitly ask it to create using application properties (quarkus.package.type=uber-jar) and using ./mvnw package -Dquarkus.package.type=uber-jar command.

The only way for creating lambda function in these cases seem to be to upload function.zip file that gets created during build process or using the native image. No fat jar option.

I am not sure if this is a bug and will raise it in Quarkus github community.

Zip file had all the dependencies required added, but is much larger is size than what I was expecting it to.

Upvotes: 1

PSchoe
PSchoe

Reputation: 76

I am not sure about your project setup but did you reference all your resources like this:

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <includes>
            <include>**/application.properties</include>
        </includes>
    </resource>
</resources>

If you have other resources you would add a additional resource.

Upvotes: 0

P&#233;ter Veres
P&#233;ter Veres

Reputation: 1163

Assuming that you are trying to run a native image it seems that the gson dependency is removed at build time.

The GraalVM responsible for quarkus native builds runs the application at build time and removes everything that it thinks to be unused in the code. This way the resulting image can be much lighter both in size and startup times.

The drawback to this is that it 'weeds out' whole libraries and even methods from your classes that seem to be unused. This is usually the case with third party libraries that does not include a jandex index.

There are many ways to overcome this. But the best way is to use the quarkus-flavored version of the libraries if they are available.

It seems that Quarkus project favors Jackson and JsonB, but there is a quarkus-camel version of Gson. Try to replace your gson dependency with this: https://camel.apache.org/camel-quarkus/latest/reference/extensions/gson.html

<dependency>
    <groupId>org.apache.camel.quarkus</groupId>
    <artifactId>camel-quarkus-gson</artifactId>
</dependency>

Upvotes: 0

Related Questions