Quarkus Native Image Build fails using AWS SDK

1.5k views Asked by At

After using the implementation of amazon sdk to interact with amazon rekognition and amazon comprehend tools, works very well on dev (mvn compile quarkus:dev), but crashes trying to make the native compilation of REST Web Service, developed using the following technologies;

GraalVM CE 22.0.0.2.

Quarkus Framework (quarkus-bom. io.quarkus.platform) 2.8.0.Final.

O.S.: Windows 10 Enterprise LTSC.

MAVEN: 3.8.4.

AWS SDK: 1.12.198.

POM 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>com.lum</groupId>
    <artifactId>casccb</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <properties>
        <compiler-plugin.version>3.8.1</compiler-plugin.version>
        <maven.compiler.release>11</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>2.8.0.Final</quarkus.platform.version>
        <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
    </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>

            <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-java-sdk-bom</artifactId>
                <version>1.12.198</version>
                <!-- <version>1.11.1000</version> -->
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>

        <!-- -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>

        <!-- -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>

        <!-- -->
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Hibernate ORM Panache -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-orm-panache</artifactId>
        </dependency>

        <!-- JDBC Driver -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-h2</artifactId>
            <!-- <artifactId>quarkus-jdbc-oracle</artifactId> -->
        </dependency>

        <!-- IO Commons -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>

        <!-- AWS sdk core -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-core</artifactId>
        </dependency>
        
        <!-- AWS s3 client -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
        </dependency>

        <!-- AWS rekognition client -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-rekognition</artifactId>
        </dependency>
        
        <!-- AWS comprehend client-->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-comprehend</artifactId>
        </dependency>

        <!-- quarkus -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-apache-httpclient</artifactId>
        </dependency>

        <!-- OpenAPI -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-openapi</artifactId>
        </dependency>

        <!-- JUnit 5 -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Mockito -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5-mockito</artifactId>
            <scope>test</scope>
        </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>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </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>

This is the output shown by the recommended x64 Native Tools Command Prompt for VS 2022. Executing "mvn package -Pnative -DskipTests=true"

Error: Unsupported features in 2 methods
    Detailed message:
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy@2ab7cc8 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.equalJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy@2aa3a8a2 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.fullJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    
    com.oracle.svm.core.util.UserError$UserException: Unsupported features in 2 methods
    Detailed message:
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy@2ab7cc8 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.equalJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy@2aa3a8a2 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.fullJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    
            at com.oracle.svm.core.util.UserError.abort(UserError.java:87)
            at com.oracle.svm.hosted.FallbackFeature.reportAsFallback(FallbackFeature.java:233)
            at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:759)
            at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:529)
            at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:488)
            at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:403)
            at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:569)
            at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:122)
            at com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus.main(NativeImageGeneratorRunner.java:599)
    Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported features in 2 methods
    Detailed message:
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy@2ab7cc8 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.equalJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
    Trace: Object was reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy.random of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy@2aa3a8a2 reached by
            reading field com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy.fullJitterBackoffStrategy of
                    constant com.amazonaws.retry.PredefinedBackoffStrategies$SDKDefaultBackoffStrategy@6a24d5e3 reached by
            reading field com.amazonaws.retry.RetryPolicy.backoffStrategy of
                    constant com.amazonaws.retry.RetryPolicy@5dc90142 reached by
            scanning method com.amazonaws.ClientConfiguration.<init>(ClientConfiguration.java:155)
    Call path from entry point to com.amazonaws.ClientConfiguration.<init>(ClientConfiguration):
            no path found from entry point to target method
    
    
            at com.oracle.graal.pointsto.constraints.UnsupportedFeatures.report(UnsupportedFeatures.java:129)
            at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:756).

P.S.: Few minutes ago applying this;

<properties>
    <quarkus.package.type>native</quarkus.package.type>
        <quarkus.native.additional-build-args>
            --initialize-at-run-time=com.amazonaws.ClientConfiguration\
                com.amazonaws.retry.PredefinedBackoffStrategies$EqualJitterBackoffStrategy\
                com.amazonaws.retry.PredefinedBackoffStrategies$FullJitterBackoffStrategy
        </quarkus.native.additional-build-args>
</properties>

It avoids several Exceptions... But it still complaining as follows;

[ERROR] Failed to execute goal io.quarkus.platform:quarkus-maven-plugin:2.8.0.Final:build (default) on project casccb: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.deployment.pkg.steps.NativeImageBuildStep#build threw an exception: io.quarkus.deployment.pkg.steps.NativeImageBuildStep$ImageGenerationFailureException: Image generation failed. Exit code: 1
[ERROR]         at io.quarkus.deployment.pkg.steps.NativeImageBuildStep.imageGenerationFailed(NativeImageBuildStep.java:396)
[ERROR]         at io.quarkus.deployment.pkg.steps.NativeImageBuildStep.build(NativeImageBuildStep.java:237)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]         at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:925)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:829)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:501).

Hope you can help me to figure out how to solve this situation.

Thanks in advance.

JJ

1

There are 1 answers

4
Guillaume Smet On

This is one of the case where you need a Quarkus extension to get things working in native.

We have extensions for Amazon Services in the Quarkiverse: https://github.com/quarkiverse/quarkus-amazon-services .

Once you have the extensions around, you can either use its config infrastructure and inject CDI beans or you can also do things all by yourself.

And you can find the documentation about these extensions here: https://quarkiverse.github.io/quarkiverse-docs/quarkus-amazon-services/dev/index.html .