Skip to content

feat: introduce ChangeDetection strategy for file copy - #397

Merged
gnodet merged 1 commit into
apache:masterfrom
gnodet:feat/change-detection
Sep 26, 2026
Merged

gnodet merged 1 commit into
apache:masterfrom
gnodet:feat/change-detection

Conversation

@gnodet

@gnodet gnodet commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Port of the ChangeDetection strategy from the maven-filtering-3.x branch (commit d9bc10a) to the master branch (Maven 4 / Path-based API).

Instead of jumping between ways to perform change detection — deciding whether an existing target file needs to be overwritten — make it a configurable strategy. Before 3.4.0 it was timestamp-based, post 3.4.0 it switched to content-based via CachingOutputStream, but in any case users were left with no control.

Changes

New ChangeDetection enum

Five strategies:

Strategy Behaviour
TIMESTAMP Overwrite only when source is newer (pre-3.4.0 default)
CONTENT Overwrite only when content differs — via CachingOutputStream/CachingWriter (current default)
TIMESTAMP_AND_CONTENT Check timestamp first, then content if needed
ALWAYS Always overwrite (replaces overwrite=true)
NEVER Never overwrite an existing file

API changes

  • AbstractMavenFilteringRequest — new changeDetection field (default CONTENT) with getter/setter
  • FilteringUtils — new copyFile(Path, Path, String, FilterWrapper[], ChangeDetection) overload returning boolean (true=written, false=skipped); old boolean overwrite signature deprecated
  • MavenFileFilter — new copyFile(…, ChangeDetection) and copyFileWithResult(…, ChangeDetection) methods; old signature deprecated
  • DefaultMavenFileFilter — implements new interface methods, returns boolean indicating whether the destination was written
  • DefaultMavenResourcesFiltering — uses getChangeDetection() from the request instead of isOverwrite(); per-resource override takes precedence over request-level setting; emits "Copying file X" or "Skipping file X (up to date)" based on the actual copy outcome
  • MavenResourcesExecution — isOverwrite() / setOverwrite() deprecated, now delegate through ChangeDetection
  • Resource — new changeDetection field so individual <resource> elements can declare their own strategy, overriding the request-level default

Implementation details

  • CONTENT / TIMESTAMP_AND_CONTENT use CachingOutputStream / CachingWriter (existing behaviour)
  • ALWAYS / TIMESTAMP / NEVER bypass caching and write unconditionally via Files.newOutputStream / Files.newBufferedWriter
  • TIMESTAMP uses Files.getLastModifiedTime(path).toMillis() for Path-based comparison
  • Per-resource changeDetection wins when set; falls back to the request-level value otherwise
  • buildContext.refresh() is always called for processed outputs so incremental build contexts (m2e / Eclipse) correctly track them regardless of whether the file was skipped

Fixes

Related

Plugin-side companion PR: apache/maven-resources-plugin#527

Origin

Ported from maven-filtering-3.x commit d9bc10a by Tamas Cservenak.

@gnodet
gnodet marked this pull request as ready for review September 24, 2026 20:49
@gnodet
gnodet force-pushed the feat/change-detection branch from 464fca5 to 2b00a7e Compare September 25, 2026 06:37

@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.

Well-structured refactor — the ChangeDetection enum is a clean replacement for the boolean overwrite flag, and the split into copyUnconditionally / copyIfContentsChanged makes the intent clear. The gracefulBinaryHandling migration from DefaultMavenFileFilter to DefaultMavenResourcesFiltering is correct (no double-handling). A few items below.

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

Comment thread src/main/java/org/apache/maven/shared/filtering/FilteringUtils.java Outdated
Comment thread src/main/java/org/apache/maven/shared/filtering/MavenResourcesExecution.java Outdated

@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.

Re-review after 4fcc417 — both previous findings are addressed:

  1. FilteringUtils.java @param overwrite — Javadoc now accurately documents the mapping (true → ALWAYS, false → CONTENT). ✅
  2. MavenResourcesExecution.java dead overwrite field — removed entirely; isOverwrite()/setOverwrite() now delegate through ChangeDetection. ✅

Full re-review of the current diff found no new issues. The switch-based dispatch in FilteringUtils.copyFile handles all five strategies correctly with a defensive default branch. The gracefulBinaryHandling migration from DefaultMavenFileFilter to DefaultMavenResourcesFiltering is clean — the caller catches MavenFilteringException wrapping MalformedInputException and falls back to unfiltered copy with the same ChangeDetection mode. API backward compat is preserved via deprecated method delegation.

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

@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.

Re-review after 9a3e681 (per-resource changeDetection override).

Previous findings (from first review): both addressed in 4fcc417 ✅

  1. FilteringUtils.java — inaccurate @param overwrite Javadoc → fixed, now documents the true→ALWAYS / false→CONTENT mapping.
  2. MavenResourcesExecution.java — dead overwrite field → removed entirely, getters/setters delegate through ChangeDetection.

New commit 9a3e681: Clean. The per-resource changeDetection override in Resource.java is nullable (null = inherit from request-level), and DefaultMavenResourcesFiltering resolves it correctly across all three call sites (flatten check, primary copy, binary-fallback copy). Field visibility is package-private, consistent with other Resource fields. Javadoc is accurate with @since 4.0.0-beta-2.

No new issues found.

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

@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.

Re-review after a25457e (accurate copy/skip debug logging).

Previous findings (from first two reviews): all addressed ✅

  1. FilteringUtils.java — inaccurate @param overwrite Javadoc → fixed in 4fcc417.
  2. MavenResourcesExecution.java — dead overwrite field → removed in 4fcc417.

New commit a25457e: adds copyFileWithResult() to MavenFileFilter (returns boolean), refactors DefaultMavenFileFilter.doCopyFile() to propagate the result, and updates DefaultMavenResourcesFiltering to log "Copying file X" vs "Skipping file X (up to date)" based on the actual copy outcome — fixing the pre-existing issue where the debug log always said "Copying" even when the file was skipped by change detection.

The gracefulBinaryHandling catch is correctly moved up to DefaultMavenResourcesFiltering for the copyFileWithResult path (retries with filtering=false), while the old doCopyFile path still handles it for backward-compatible callers via copyFile(MavenFileFilterRequest). No double-handling.

No new issues found.

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

@gnodet
gnodet force-pushed the feat/change-detection branch from a25457e to dec4590 Compare September 25, 2026 15:10

@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.

Re-review after rebase/squash (dec4590). Tree SHA is identical to previously approved a25457e — code unchanged, all prior findings remain addressed. Clean rebase onto updated master.

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

@gnodet gnodet added enhancement New feature or request java Pull requests that update Java code labels Sep 26, 2026
…S-397)

Replace the boolean overwrite parameter with a ChangeDetection enum that
supports ALWAYS, NEVER, TIMESTAMP, CONTENT, and TIMESTAMP_AND_CONTENT modes.

- Add ChangeDetection enum with five strategies
- Add MavenResourcesExecution.changeDetection field (default: CONTENT)
- Add per-resource Resource.changeDetection override
- Adapt MavenFileFilter / DefaultMavenFileFilter APIs (boolean overwrite overloads deprecated)
- FilteringUtils.copyFile: return boolean (was copied or skipped)
- Fix debug log to report actual copy/skip outcome per file
@gnodet
gnodet force-pushed the feat/change-detection branch from dec4590 to 4baf4b4 Compare September 26, 2026 17:11
@gnodet
gnodet merged commit e5c3765 into apache:master Sep 26, 2026
1 of 2 checks passed
@github-actions github-actions Bot added this to the 4.0.0-beta-2 milestone Sep 26, 2026
gnodet added a commit to apache/maven-resources-plugin that referenced this pull request Sep 26, 2026
Replace the deprecated boolean 'overwrite' parameter with a 'changeDetection'
strategy enum (CONTENT / TIMESTAMP / TIMESTAMP_AND_CONTENT / ALWAYS / NEVER),
forwarded from maven-filtering 4.0.0-beta-2-SNAPSHOT (PR apache/maven-filtering#397).

- Add 'changeDetection' @parameter (default CONTENT, i.e. current behaviour)
- Deprecate 'overwrite'; bridge: overwrite=true maps to ALWAYS, overwrite=false
  keeps the declared changeDetection value (backward-compat)
- Add IT MRESOURCES-453: verifies that changeDetection=NEVER leaves an existing
  destination file untouched even when source content differs

Fixes: #453
Depends on: apache/maven-filtering#397
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request java Pull requests that update Java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants