Skip to content

Latest commit

 

History

History
86 lines (71 loc) · 5.01 KB

File metadata and controls

86 lines (71 loc) · 5.01 KB

GraalVM Compatibility for AWS Lambda Powertools Java

Table of Contents

Overview

This documentation provides guidance for adding GraalVM support for AWS Lambda Powertools Java modules and using the modules in Lambda functions.

Prerequisites

  • GraalVM 21+ installation
  • Maven 3.x

General Implementation Steps

GraalVM native image compilation requires complete knowledge of an application's dynamic features at build time. The GraalVM reachability metadata (GRM) JSON files are essential because Java applications often use features that are determined at runtime, such as reflection, dynamic proxy classes, resource loading, and JNI (Java Native Interface). The metadata files tell GraalVM which classes need reflection access, which resources need to be included in the native image, and which proxy classes need to be generated.

In order to generate the metadata reachability files for Powertools for Lambda, follow these general steps.

  1. Add Maven Profiles

    • Add profile for generating GraalVM reachability metadata files. You can find an example of this in profile generate-graalvm-files of this pom.xml.
    • Add another profile for running the tests in the native image. You can find and example of this in profile graalvm-native of this pom.xml.
  2. Generate Reachability Metadata

    • Set the JAVA_HOME environment variable to use GraalVM
    • Run tests with -Pgenerate-graalvm-files profile.
mvn -Pgenerate-graalvm-files clean test
  1. Validate Native Image Tests
    • Set the JAVA_HOME environment variable to use GraalVM
    • Run tests with -Pgraalvm-native profile. This will build a GraalVM native image and run the JUnit tests.
mvn -Pgraalvm-native clean test
  1. Clean Up Metadata
    • GraalVM metadata reachability files generated in Step 2 contains references to the test scoped dependencies as well.
    • Remove the references in generated metadata files for the following (and any other references to test scoped resources and classes):
      • JUnit
      • Mockito
      • ByteBuddy

Known Issues and Solutions

  1. Mockito Compatibility

    • Powertools uses Mockito 5.x which uses “inline mock maker” as the default. This mock maker does not play well with GraalVM. Mockito recommends using subclass mock maker with GraalVM. Therefore generate-graalvm-files profile uses subclass mock maker instead of inline mock maker.
    • Subclass mock maker does not support testing static methods. Tests have therefore been modified to use JUnit Pioneer to inject the environment variables in the scope of the test's execution.
  2. Log4j Compatibility

    • Version 2.22.1 fails with this error
java.lang.InternalError: com.oracle.svm.core.jdk.UnsupportedFeatureError: Defining hidden classes at runtime is not supported.
  • This has been fixed in Log4j 2.24.x. PT has been updated to use this version of Log4j
  1. Test Class Organization

    • Issue: Anonymous inner classes and lambda expressions in Mockito matchers cause NoSuchMethodError in GraalVM native tests
    • Solution:
      • Extract static inner test classes to separate concrete classes in the same package as the class under test
      • Replace lambda expressions in ArgumentMatcher with concrete implementations
      • Use mockito-subclass dependency in GraalVM profiles
    • Example: Replace argThat(resp -> resp.getStatus() != expectedStatus) with:
    argThat(new ArgumentMatcher<Response>() {
        @Override
        public boolean matches(Response resp) {
            return resp != null && resp.getStatus() != expectedStatus;
        }
    })
  2. Package Visibility Issues

    • Issue: Test handler classes cannot access package-private methods when placed in subpackages
    • Solution: Place test handler classes in the same package as the class under test, not in subpackages like handlers/
    • Example: Use software.amazon.lambda.powertools.cloudformation instead of software.amazon.lambda.powertools.cloudformation.handlers
  3. Test Stubs Best Practice

    • Best Practice: Avoid mocking where possible and use concrete test stubs provided by powertools-common package
    • Solution: Use TestLambdaContext and other test stubs from powertools-common test-jar instead of Mockito mocks
    • Implementation: Add powertools-common test-jar dependency and replace mock(Context.class) with new TestLambdaContext()

Reference Implementation

Working example is available in the examples.