Motivation
Native Build Tools already has the right high-level dependency direction: the Gradle and Maven plugins depend on build-tool-neutral common libraries. However, important shared Native Image semantics are still assembled independently in the two adapters.
In particular:
- Gradle's
NativeImageCommandLineProvider and Maven's AbstractNativeImageMojo independently construct the classpath, standard flags, output path, system/JVM properties, configuration directories, argument file, and trailing main class.
NativeImagePlugin has grown into a large composition root containing registration, native tests, agents, metadata, toolchain, layer, and compatibility-mode wiring.
- Maven-specific helpers are packaged under
org.graalvm.buildtools.utils, creating a split package with the published common-utils dependency.
MissingMetadataCommandSupport combines domain analysis, rendering, GitHub/Maven Central HTTP integration, authentication, and repository discovery.
- Parity is specified and covered by separate functional suites, but there is no shared contract suite that proves equivalent requests produce equivalent Native Image plans.
This makes Gradle/Maven behavior easier to drift, raises the cost of adding shared features, and pushes too much verification into expensive end-to-end tests.
Proposed target architecture
Introduce a build-tool-neutral planning boundary:
Gradle model ----\
-> NativeBuildRequest -> NativeImagePlanner -> InvocationPlan
Maven model -----/ |
adapter-specific process execution
The shared planner should operate only on plain Java values. Gradle remains responsible for providers, task inputs/outputs, services, and ExecOperations; Maven remains responsible for project/lifecycle/toolchain integration and Mojo error translation.
This is an umbrella architecture issue. Large implementation phases may be tracked as linked follow-up issues.
Scope
1. Specify and introduce shared planning types
- Update the most-specific grund functional and architecture points before changing code.
- Add immutable build-tool-neutral request/plan types for common Native Image invocation semantics.
- Centralize standard flag, classpath, output, property, configuration-directory, argument-file, and main-class ordering semantics in a pure planner.
- Keep build-tool-specific option collection and process execution in the adapters.
2. Adapt Gradle and Maven incrementally
- Translate finalized Gradle provider values into the shared request.
- Translate Maven Mojo/project state into the shared request.
- Migrate one semantic slice at a time while preserving existing task, DSL, goal, parameter, and diagnostic compatibility.
3. Harden ownership boundaries
- Move Maven-only helpers from
org.graalvm.buildtools.utils to org.graalvm.buildtools.maven.internal (with compatibility bridges if required).
- Decompose
NativeImagePlugin into focused internal feature/configuration components while keeping the public plugin class as the composition root.
- Make Maven Mojos thin parameter/descriptor adapters that delegate execution behavior to focused services.
- Split missing-metadata analysis/reporting from GitHub, Maven Central, and repository-discovery adapters.
4. Enforce the architecture
- Add shared planner/contract tests covering parity-sensitive scenarios.
- Retain real Gradle TestKit and Maven functional tests for adapter and end-to-end behavior.
- Add automated dependency/package checks: common code must not import Gradle or Maven APIs, product plugins must not depend on each other, and published artifacts must not create split packages.
- Add an API compatibility baseline for public common/Gradle APIs and the Maven plugin descriptor.
Non-goals
- Creating a shared Gradle/Maven user-facing DSL.
- Making common code depend on Gradle or Maven APIs.
- Replacing idiomatic Gradle provider/task wiring or Maven lifecycle/toolchain integration.
- Changing existing user-visible behavior as part of the structural migration.
- Splitting every package into a separately published artifact upfront.
Acceptance criteria
Suggested implementation order
- Architecture/spec update and shared request/plan skeleton.
- Basic command-line planning and pure unit tests.
- Gradle and Maven adapters plus parity contract tests.
- Split-package removal and entry-point/Mojo decomposition.
- Missing-metadata ports/adapters and API/architecture enforcement.
Motivation
Native Build Tools already has the right high-level dependency direction: the Gradle and Maven plugins depend on build-tool-neutral common libraries. However, important shared Native Image semantics are still assembled independently in the two adapters.
In particular:
NativeImageCommandLineProviderand Maven'sAbstractNativeImageMojoindependently construct the classpath, standard flags, output path, system/JVM properties, configuration directories, argument file, and trailing main class.NativeImagePluginhas grown into a large composition root containing registration, native tests, agents, metadata, toolchain, layer, and compatibility-mode wiring.org.graalvm.buildtools.utils, creating a split package with the published common-utils dependency.MissingMetadataCommandSupportcombines domain analysis, rendering, GitHub/Maven Central HTTP integration, authentication, and repository discovery.This makes Gradle/Maven behavior easier to drift, raises the cost of adding shared features, and pushes too much verification into expensive end-to-end tests.
Proposed target architecture
Introduce a build-tool-neutral planning boundary:
The shared planner should operate only on plain Java values. Gradle remains responsible for providers, task inputs/outputs, services, and
ExecOperations; Maven remains responsible for project/lifecycle/toolchain integration and Mojo error translation.This is an umbrella architecture issue. Large implementation phases may be tracked as linked follow-up issues.
Scope
1. Specify and introduce shared planning types
2. Adapt Gradle and Maven incrementally
3. Harden ownership boundaries
org.graalvm.buildtools.utilstoorg.graalvm.buildtools.maven.internal(with compatibility bridges if required).NativeImagePlugininto focused internal feature/configuration components while keeping the public plugin class as the composition root.4. Enforce the architecture
Non-goals
Acceptance criteria
grund check.Suggested implementation order