diff --git a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java index 0a2d4d73..b3d00be7 100644 --- a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java +++ b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java @@ -379,7 +379,7 @@ boolean isParamsMatched( Path baseDirPath = project.getBasedir().toPath(); currentValue = normalizedPath(((Path) value), baseDirPath); } else if (value != null && value.getClass().isArray()) { - currentValue = ArrayUtils.toString(value); + currentValue = filterAndStringifyArray(value, trackedProperty.getIgnorePattern()); } else { currentValue = String.valueOf(value); } @@ -388,7 +388,13 @@ boolean isParamsMatched( return false; } - if (!Strings.CS.equals(currentValue, expectedValue)) { + // Apply ignorePattern filtering to expected value if it's an array string representation + String filteredExpectedValue = expectedValue; + if (trackedProperty.getIgnorePattern() != null && expectedValue.startsWith("[") && expectedValue.endsWith("]")) { + filteredExpectedValue = filterArrayString(expectedValue, trackedProperty.getIgnorePattern()); + } + + if (!Strings.CS.equals(currentValue, filteredExpectedValue)) { if (!Strings.CS.equals(currentValue, trackedProperty.getSkipValue())) { LOGGER.info( "Plugin parameter mismatch found. Parameter: {}, expected: {}, actual: {}", @@ -434,6 +440,55 @@ private static String normalizedPath(Path path, Path baseDirPath) { return normalizedPath; } + /** + * Filters array values based on ignore pattern and converts to string representation. + */ + private static String filterAndStringifyArray(Object array, String ignorePattern) { + if (ignorePattern == null) { + return ArrayUtils.toString(array); + } + + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(ignorePattern); + java.util.List filtered = new java.util.ArrayList<>(); + + int length = java.lang.reflect.Array.getLength(array); + for (int i = 0; i < length; i++) { + Object element = java.lang.reflect.Array.get(array, i); + String elementStr = String.valueOf(element); + if (!pattern.matcher(elementStr).find()) { + filtered.add(element); + } + } + + return filtered.toString(); + } + + /** + * Filters an array string representation (e.g., "[a, b, c]") based on ignore pattern. + */ + private static String filterArrayString(String arrayStr, String ignorePattern) { + if (ignorePattern == null || !arrayStr.startsWith("[") || !arrayStr.endsWith("]")) { + return arrayStr; + } + + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(ignorePattern); + String content = arrayStr.substring(1, arrayStr.length() - 1); + if (content.trim().isEmpty()) { + return "[]"; + } + + String[] elements = content.split(",\\s*"); + java.util.List filtered = new java.util.ArrayList<>(); + + for (String element : elements) { + if (!pattern.matcher(element.trim()).find()) { + filtered.add(element.trim()); + } + } + + return filtered.toString(); + } + private enum CacheRestorationStatus { SUCCESS, FAILURE, diff --git a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java index cd6e87c0..bfe591a1 100644 --- a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java +++ b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java @@ -248,18 +248,15 @@ public boolean isLogAllProperties(MojoExecution mojoExecution) { } private GoalReconciliation findReconciliationConfig(MojoExecution mojoExecution) { - if (cacheConfig.getExecutionControl() == null) { - return null; - } + List reconciliation; - final ExecutionControl executionControl = cacheConfig.getExecutionControl(); - if (executionControl.getReconcile() == null) { - return null; + if (cacheConfig.getExecutionControl() == null || cacheConfig.getExecutionControl().getReconcile() == null) { + // Use default reconciliation configs for common plugins + reconciliation = getDefaultReconciliationConfigs(); + } else { + reconciliation = cacheConfig.getExecutionControl().getReconcile().getPlugins(); } - final List reconciliation = - executionControl.getReconcile().getPlugins(); - for (GoalReconciliation goalReconciliationConfig : reconciliation) { final String goal = mojoExecution.getGoal(); @@ -271,6 +268,68 @@ private GoalReconciliation findReconciliationConfig(MojoExecution mojoExecution) return null; } + private List getDefaultReconciliationConfigs() { + List defaults = new ArrayList<>(); + + // maven-compiler-plugin:compile - track source, target, release, compilerArgs + GoalReconciliation compilerCompile = new GoalReconciliation(); + compilerCompile.setArtifactId("maven-compiler-plugin"); + compilerCompile.setGoal("compile"); + + TrackedProperty source = new TrackedProperty(); + source.setPropertyName("source"); + compilerCompile.addReconcile(source); + + TrackedProperty target = new TrackedProperty(); + target.setPropertyName("target"); + compilerCompile.addReconcile(target); + + TrackedProperty release = new TrackedProperty(); + release.setPropertyName("release"); + compilerCompile.addReconcile(release); + + // Track compilerArgs but filter out --module-version to handle Maven 4 auto-injection (issue #375) + TrackedProperty compilerArgs = new TrackedProperty(); + compilerArgs.setPropertyName("compilerArgs"); + compilerArgs.setIgnorePattern("--module-version"); + compilerCompile.addReconcile(compilerArgs); + + defaults.add(compilerCompile); + + // maven-compiler-plugin:testCompile - track source, target, release, compilerArgs + GoalReconciliation compilerTestCompile = new GoalReconciliation(); + compilerTestCompile.setArtifactId("maven-compiler-plugin"); + compilerTestCompile.setGoal("testCompile"); + + TrackedProperty testSource = new TrackedProperty(); + testSource.setPropertyName("source"); + compilerTestCompile.addReconcile(testSource); + + TrackedProperty testTarget = new TrackedProperty(); + testTarget.setPropertyName("target"); + compilerTestCompile.addReconcile(testTarget); + + TrackedProperty testRelease = new TrackedProperty(); + testRelease.setPropertyName("release"); + compilerTestCompile.addReconcile(testRelease); + + // Track compilerArgs but filter out --module-version to handle Maven 4 auto-injection (issue #375) + TrackedProperty testCompilerArgs = new TrackedProperty(); + testCompilerArgs.setPropertyName("compilerArgs"); + testCompilerArgs.setIgnorePattern("--module-version"); + compilerTestCompile.addReconcile(testCompilerArgs); + + defaults.add(compilerTestCompile); + + // maven-install-plugin:install - always run (empty reconciliation means it's tracked) + GoalReconciliation install = new GoalReconciliation(); + install.setArtifactId("maven-install-plugin"); + install.setGoal("install"); + defaults.add(install); + + return defaults; + } + @Nonnull @Override public List getLoggedProperties(MojoExecution mojoExecution) { diff --git a/src/main/mdo/build-cache-config.mdo b/src/main/mdo/build-cache-config.mdo index 52ae0da0..25034119 100644 --- a/src/main/mdo/build-cache-config.mdo +++ b/src/main/mdo/build-cache-config.mdo @@ -1459,6 +1459,11 @@ under the License. defaultValue String + + ignorePattern + String + Regular expression pattern to filter out matching values from array/list properties before comparison. Useful for filtering auto-injected values like Maven 4's --module-version + diff --git a/src/site/markdown/how-to.md b/src/site/markdown/how-to.md index a4ebbb78..e036c9c1 100644 --- a/src/site/markdown/how-to.md +++ b/src/site/markdown/how-to.md @@ -160,6 +160,17 @@ Add `executionControl/runAlways` section: ``` +### Default Reconciliation Behavior + +The build cache extension automatically tracks certain critical plugin properties by default, even without explicit +`executionControl` configuration: + +* **maven-compiler-plugin** (`compile` and `testCompile` goals): Tracks `source`, `target`, and `release` properties +* **maven-install-plugin** (`install` goal): Tracked to ensure artifacts are installed when needed + +This default behavior prevents common cache invalidation issues, particularly in multi-module JPMS (Java Platform Module System) +projects where compiler version changes can cause compilation failures. + ### I occasionally cached build with `-DskipTests=true`, and tests do not run now If you add command line flags to your build, they do not participate in effective pom - Maven defers the final value