Skip to content

[DO NOT MERGE] experiment: leverage BuildContext API for incremental JAR creation - #566

Draft
gnodet wants to merge 2 commits into
masterfrom
experiment/maven4-build-context
Draft

gnodet wants to merge 2 commits into
masterfrom
experiment/maven4-build-context

Conversation

@gnodet

@gnodet gnodet commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Integrate the Maven 4 BuildContext API to skip JAR creation when no input files have changed since the last build
  • When forceCreation is false and the JAR file already exists, the plugin registers and scans the classes directory via BuildContext.registerAndProcessInputs() and skips re-packaging if all inputs are UNMODIFIED
  • Signals markSkipExecution() at all skip points (skipIfEmpty, unchanged inputs) so downstream mojos can react accordingly

Details

This is an experimental branch that depends on:

Changes

  • AbstractJarMojo.java: Added @Inject BuildContext buildContext field, hasChangedInputs() method that uses registerAndProcessInputs() to detect file changes, and attachArtifact() helper. The execute() method now checks for changed inputs before creating the JAR.
  • TestJarMojo.java: Added markSkipExecution() in the skip branch
  • JarMojoTest.java: Updated test imports to new org.apache.maven.testing.plugin package, added @Provides methods for BuildContext and PathMatcherFactory
  • pom.xml: Bumped mavenVersion to 4.1.0-SNAPSHOT

Test plan

  • All existing tests pass (1/1)
  • Integration testing with a multi-module project to verify JAR skipping

🤖 Generated with Claude Code

gnodet and others added 2 commits July 29, 2026 16:17
Integrate the Maven 4 BuildContext API to skip JAR creation when no
input files have changed since the last build. When forceCreation is
false and the JAR file already exists, the plugin now registers and
scans the classes directory via BuildContext.registerAndProcessInputs()
and skips re-packaging if all inputs are UNMODIFIED.

Also signals markSkipExecution() at all skip points (skipIfEmpty,
unchanged inputs) so downstream mojos can react accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the ad-hoc hasChangedInputs() check with the BuildContext
InputSet aggregation pattern. This correctly registers all class files
as inputs, associates them with the JAR output file, and lets the
build context handle stale output cleanup when inputs are removed.

Previously, inputs were registered via registerAndProcessInputs() but
the JAR was never associated as an output — breaking the input→output
tracking that enables BuildContext's stale output cleanup. The
aggregate() pattern is the correct fit for many-inputs-to-one-output
transformations like JAR packaging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet changed the title experiment: leverage BuildContext API for incremental JAR creation [DO NOT MERGE] experiment: leverage BuildContext API for incremental JAR creation Sep 25, 2026

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incremental JAR creation via BuildContext — the approach is sound, but the input registration has a pattern mismatch that will cause false rebuilds (or missed rebuilds with custom includes/excludes).

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment on lines +337 to +338
InputSet inputSet = buildContext.newInputSet();
inputSet.registerInputs(classesDir, List.of("**/**"), List.of());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Input pattern mismatch. registerInputs() uses hardcoded "**/**" with no excludes, but createArchive() uses getIncludes()/getExcludes() — which at minimum excludes **/package.html by default, and may exclude/include user-configured patterns.

This means:

  • A change to package.html (excluded from JAR) triggers a needless rebuild
  • With custom <includes>, changes to files outside the include set still trigger rebuilds
  • The incremental detection tracks a superset of what actually enters the JAR
Suggested change
InputSet inputSet = buildContext.newInputSet();
inputSet.registerInputs(classesDir, List.of("**/**"), List.of());
InputSet inputSet = buildContext.newInputSet();
inputSet.registerInputs(classesDir, Arrays.asList(getIncludes()), Arrays.asList(getExcludes()));

Comment on lines +340 to +342
boolean rebuilt = inputSet.aggregate(jarFile, (output, inputs) -> {
createArchive();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Aggregate callback ignores both output and inputs parameters. createArchive() independently recomputes basedir/finalName/jarFile and writes to its own path. The Output resource provided by the BuildContext (which is the tracked output file) is never used.

If the two path computations ever diverge, the BuildContext would track one file while the actual JAR lives at another. Consider either:

  1. Refactoring createArchive() to accept a target Path parameter, or
  2. Using the Output to get the canonical path and passing it through

Also, using (output, inputs) -> with unused params — if this is intentional, a brief comment explaining why would help future readers.

@@ -47,4 +56,19 @@ void jarTestEnvironment(JarMojo mojo) throws Exception {

assertEquals("foo", mojo.getProject().getGroupId());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 The existing test only verifies mojo wiring (assertNotNull, groupId equality). There's no test for the new incremental execute() path — no coverage for:

  • aggregate() being called and creating a JAR on first build
  • markSkipExecution() firing when inputs are unchanged
  • forceCreation = true bypassing the incremental check

Given this is the core new behavior, at least one test exercising the BuildContext integration would catch regressions early. (Acknowledged this is experimental — flagging for when it graduates.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants