Skip to content

Maintenance: Modernize GraalVM native-image test infrastructure #2416

@phipag

Description

@phipag

Summary

  1. The generate-graalvm-files and graalvm-native Maven profiles can be consolidated into a single profile using the native-maven-plugin's built-in <agent> configuration.
  2. GraalVM 21.0.10 introduced stricter unsafeAllocated enforcement in reflect-config.json. Mockito uses Objenesis → Unsafe.allocateInstance() which the tracing agent does not detect. This broke powertools-cloudformation native tests (PR chore: bump com.fasterxml.jackson:jackson-bom from 2.20.1 to 2.21.1 #2403). CI was pinned to GraalVM 21.0.8 as a quick fix.

Why is this needed?

  • The two-profile approach requires two Maven invocations per module in CI, adding complexity and build time.
  • Pinning to GraalVM 21.0.8 is a temporary workaround.

Which area does this relate to?

Governance

Action Items

1. Modernize to single profile with -Dagent=true

Consolidate into a single graalvm-native profile across all 17+ modules.

Current approach (two profiles, two Maven invocations):

mvn -Pgenerate-graalvm-files clean test
mvn -Pgraalvm-native test

Target approach (single profile):

mvn -Pgraalvm-native -Dagent=true clean test
mvn -Pgraalvm-native native:metadata-copy
mvn -Pgraalvm-native test

Plugin configuration (replaces generate-graalvm-files profile):

<configuration>
    <agent>
        <enabled>true</enabled>
        <options>
            <enableExperimentalPredefinedClasses>true</enableExperimentalPredefinedClasses>
            <enableExperimentalUnsafeAllocationTracing>true</enableExperimentalUnsafeAllocationTracing>
        </options>
        <metadataCopy>
            <disabledStages>
                <stage>main</stage>
            </disabledStages>
            <merge>true</merge>
            <outputDirectory>src/main/resources/META-INF/native-image/software.amazon.lambda/MODULE_NAME</outputDirectory>
        </metadataCopy>
    </agent>
</configuration>

After migration:

  • Remove generate-graalvm-files profile from all modules
  • Simplify check-build.yml
  • Update GraalVM.md

2. Investigate and fix the unsafeAllocated issue

GraalVM 21.0.10+ requires "unsafeAllocated": true in reflect-config.json for classes instantiated via Unsafe.allocateInstance(). Mockito uses Objenesis which relies on this, and the tracing agent does not detect it.

Current workaround: CI pinned to GraalVM 21.0.8.

Solutions (in order of preference):

  1. Investigate enableExperimentalUnsafeAllocationTracing. The native-build-tools plugin has had this option for ~3 years (source). It maps to experimental-unsafe-allocation-support in the agent. Investigate if this can be leveraged to fix the issue. This is the most preferred option.

  2. Post-processing script. A jq-based script that patches reflect-config.json after agent generation. Adds CI complexity, not recommended.

  3. Replace mocks with test doubles. Last resort. Requires rewriting tests across all affected modules.

References

Acknowledgment

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Working on it

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions