cowwoc opened a new pull request, #395:
URL: https://github.com/apache/maven-build-cache-extension/pull/395
## Problem
Maven 4 automatically injects `--module-version ${project.version}` into
compiler arguments **during execution**, but the build cache validates
properties **before execution**. This creates a timing mismatch that causes
cache invalidation:
- **First build**: No cache exists → properties captured during/after
execution (WITH Maven 4 injection)
- **Second build**: Cache exists → properties captured during validation
(WITHOUT injection yet) → mismatch → cache invalidated
## Root Cause Analysis
The cache extension currently reads plugin properties at **different
lifecycle points** for different builds:
```
First Build Timeline:
1. findCachedBuild() → no cache found
2. Mojos execute → Maven 4 injects --module-version
3. beforeMojoExecution() fires → captures properties WITH injection
4. save() stores properties from execution events
Second Build Timeline:
1. findCachedBuild() → cache found
2. verifyCacheConsistency() → creates mojo via getConfiguredMojo()
3. Reads properties → WITHOUT injection (too early in lifecycle)
4. Compares to first build's stored values (WITH injection)
5. MISMATCH → cache invalidated!
```
The problem: **validation reads BEFORE injection, storage reads AFTER
injection**.
## Solution
Capture properties at **validation time** for ALL builds (even when no cache
exists). This ensures both validation and storage read at the same lifecycle
point.
### Implementation
1. **Modified `CacheResult`** to store validation-time mojo events
2. **Modified `BuildCacheMojosExecutionStrategy`** to capture properties
immediately after `findCachedBuild()`
3. **Modified `save()`** to use validation-time events instead of
execution-time events
### Key Code Changes
```java
// In BuildCacheMojosExecutionStrategy.execute():
result = cacheController.findCachedBuild(session, project, mojoExecutions,
skipCache);
// NEW: Capture validation-time properties for ALL mojos
Map<String, MojoExecutionEvent> validationTimeEvents =
captureValidationTimeProperties(session, project, mojoExecutions);
// Store in result
result = CacheResult.rebuilded(result, validationTimeEvents);
```
```java
// In save():
// Use validation-time events instead of execution-time events
Map<String, MojoExecutionEvent> propertyEvents =
cacheResult.getValidationTimeEvents() != null
? cacheResult.getValidationTimeEvents() // Use validation-time
: executionEvents; // Fallback to
execution-time
List<CompletedExecution> completedExecution =
buildExecutionInfo(mojoExecutions, propertyEvents);
```
### New Timeline (Both Builds)
```
First Build:
1. findCachedBuild() → no cache
2. captureValidationTimeProperties() → reads WITHOUT injection
3. Mojos execute → Maven 4 injects (but we don't use these values)
4. save() uses validation-time properties → stores WITHOUT injection
Second Build:
1. findCachedBuild() → cache found
2. verifyCacheConsistency() → reads WITHOUT injection
3. captureValidationTimeProperties() → reads WITHOUT injection
4. Compares to first build → BOTH without injection → MATCH!
```
## Benefits Over PR #391
| Aspect | PR #391 (`ignorePattern`) | This PR (Validation-Time Capture) |
|--------|--------------------------|-----------------------------------|
| **Approach** | Workaround: Filter mismatched values | Fix: Eliminate
timing mismatch |
| **Configuration** | Required | None needed |
| **Flexibility** | Pattern must match version format | Format-agnostic |
| **Maintenance** | Patterns need updates | No maintenance |
| **Scope** | Only fixes known patterns | Fixes ALL auto-injected properties
|
## Testing
Created comprehensive integration tests:
1. **Maven4JpmsModuleTest** - JPMS module with Maven 4 auto-injection of
`--module-version`
2. **ExplicitModuleVersionTest** - JPMS module with explicit `moduleVersion`
configuration
3. **NonJpmsProjectTest** - Regular Java project without JPMS (ensures no
regression)
4. **MultiModuleJpmsTest** - Multi-module project with mixed JPMS and
non-JPMS modules
All tests verify:
- ✅ First build creates cache
- ✅ Second build restores from cache (NO cache invalidation)
- ✅ NO `ignorePattern` configuration required
## Backward Compatibility
- Fully backward compatible
- Existing caches remain valid
- No configuration changes required
- `ignorePattern` still works but is no longer necessary for Maven 4
injection
## Alternative Approaches Considered
1. **Store validation-time values only** ❌ - Would lose auditability of what
actually executed
2. **Delay validation until execution** ❌ - Would lose early cache-miss
detection performance
3. **Pattern-based filtering (PR #391)** ❌ - Treats symptom, not root cause
4. **Maven core changes** ❌ - Outside our control
5. **Validation-time capture (this PR)** ✅ - Fixes root cause, no
configuration needed
## Related Issues
- Fixes #375
- Alternative to #391
- Related to Maven 4 JPMS module compilation
## Migration
No migration needed. This change is transparent to users. Existing projects
will benefit automatically.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]