You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/06/18 13:05:03 UTC

(maven) branch maven-4.0.x updated: Add deprecated property replacement (${version} → ${project.version}) to mvnup (#12308)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch maven-4.0.x
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/maven-4.0.x by this push:
     new fe2a85addf Add deprecated property replacement (${version} → ${project.version}) to mvnup (#12308)
fe2a85addf is described below

commit fe2a85addfbbba7cbfab0196a3660a44b1bbdf01
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Jun 18 15:04:57 2026 +0200

    Add deprecated property replacement (${version} → ${project.version}) to mvnup (#12308)
    
    Maven 3 supported ${version}, ${groupId}, and ${artifactId} as shorthand
    aliases for their ${project.*} equivalents. Maven 4 drops these deprecated
    aliases (see apache/maven#12304), causing builds to fail.
    
    Add fixDeprecatedPropertyExpressions() to CompatibilityFixStrategy that
    scans all text content in the POM and replaces the deprecated expressions
    with their ${project.*} equivalents. This fix runs before the undefined
    property expression check so that already-replaced expressions are not
    falsely flagged.
    
    Co-authored-by: Claude Sonnet 4.6 <no...@anthropic.com>
---
 .../mvnup/goals/CompatibilityFixStrategy.java      |  41 +++++
 .../mvnup/goals/CompatibilityFixStrategyTest.java  | 197 +++++++++++++++++++++
 2 files changed, 238 insertions(+)

diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java
index 6b9b0c8e39..9b52f5d062 100644
--- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java
+++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java
@@ -147,6 +147,7 @@ public UpgradeResult doApply(UpgradeContext context, Map<Path, Document> pomMap)
                 hasIssues |= fixDuplicateDependencies(pomDocument, context);
                 hasIssues |= fixDuplicatePlugins(pomDocument, context);
                 hasIssues |= fixUnsupportedRepositoryExpressions(pomDocument, context);
+                hasIssues |= fixDeprecatedPropertyExpressions(pomDocument, context);
                 hasIssues |= fixIncorrectParentRelativePaths(pomDocument, pomPath, pomMap, context);
                 hasIssues |= fixUndefinedPropertyExpressions(pomDocument, allDefinedProperties, context);
                 hasIssues |= fixUndefinedPropertyExpressionsInRepositories(pomDocument, allDefinedProperties, context);
@@ -759,6 +760,46 @@ private boolean fixRepositoryExpressions(
         return fixed;
     }
 
+    /**
+     * Fixes deprecated Maven 2/3 shorthand property expressions throughout the POM.
+     * Replaces ${version}, ${groupId}, and ${artifactId} with their ${project.*} equivalents,
+     * which are the only forms supported in Maven 4.
+     */
+    private boolean fixDeprecatedPropertyExpressions(Document pomDocument, UpgradeContext context) {
+        return fixDeprecatedPropertyExpressionsInElement(pomDocument.root(), context);
+    }
+
+    private boolean fixDeprecatedPropertyExpressionsInElement(Element element, UpgradeContext context) {
+        boolean fixed = false;
+
+        List<Element> children = element.childElements().toList();
+
+        if (children.isEmpty()) {
+            String text = element.textContent();
+            if (text != null && !text.isEmpty()) {
+                String fixedText = replaceDeprecatedExpressions(text);
+                if (!fixedText.equals(text)) {
+                    element.textContent(fixedText);
+                    context.detail("Fixed: replaced deprecated property expression in <" + element.name() + ">: "
+                            + text.trim() + " → " + fixedText.trim());
+                    fixed = true;
+                }
+            }
+        } else {
+            for (Element child : children) {
+                fixed |= fixDeprecatedPropertyExpressionsInElement(child, context);
+            }
+        }
+
+        return fixed;
+    }
+
+    private static String replaceDeprecatedExpressions(String text) {
+        return text.replace("${version}", "${project.version}")
+                .replace("${groupId}", "${project.groupId}")
+                .replace("${artifactId}", "${project.artifactId}");
+    }
+
     private Path findParentPomInMap(
             UpgradeContext context, String groupId, String artifactId, String version, Map<Path, Document> pomMap) {
         return pomMap.entrySet().stream()
diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java
index 3b8e7fc9a0..2d1e6a6332 100644
--- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java
+++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java
@@ -1632,6 +1632,203 @@ void shouldNotCommentOutRepositoryWithWellKnownProperty() throws Exception {
         }
     }
 
+    @Nested
+    @DisplayName("Deprecated Property Expression Fixes")
+    class DeprecatedPropertyExpressionFixesTests {
+
+        @Test
+        @DisplayName("should replace ${version} with ${project.version} in dependency version")
+        void shouldReplaceVersionExpression() throws Exception {
+            String pomXml = """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <project xmlns="http://maven.apache.org/POM/4.0.0">
+                    <modelVersion>4.0.0</modelVersion>
+                    <groupId>test</groupId>
+                    <artifactId>test</artifactId>
+                    <version>1.0.0</version>
+                    <dependencyManagement>
+                        <dependencies>
+                            <dependency>
+                                <groupId>test</groupId>
+                                <artifactId>test-dep</artifactId>
+                                <version>${version}</version>
+                            </dependency>
+                        </dependencies>
+                    </dependencyManagement>
+                    <build>
+                        <plugins>
+                            <plugin>
+                                <groupId>org.apache.maven.plugins</groupId>
+                                <artifactId>maven-jar-plugin</artifactId>
+                                <version>${version}</version>
+                            </plugin>
+                        </plugins>
+                    </build>
+                </project>
+                """;
+
+            Document document = Document.of(pomXml);
+            Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document);
+
+            UpgradeContext context = createMockContext();
+            UpgradeResult result = strategy.doApply(context, pomMap);
+
+            assertTrue(result.success(), "Compatibility fix should succeed");
+            assertTrue(result.modifiedCount() > 0, "Should have fixed deprecated ${version}");
+
+            String xml = DomUtils.toXml(document);
+            assertFalse(xml.contains("${version}"), "Should not contain deprecated ${version}");
+            assertTrue(xml.contains("${project.version}"), "Should contain ${project.version}");
+        }
+
+        @Test
+        @DisplayName("should replace ${groupId} and ${artifactId} expressions")
+        void shouldReplaceGroupIdAndArtifactIdExpressions() throws Exception {
+            String pomXml = """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <project xmlns="http://maven.apache.org/POM/4.0.0">
+                    <modelVersion>4.0.0</modelVersion>
+                    <groupId>com.example</groupId>
+                    <artifactId>my-project</artifactId>
+                    <version>1.0.0</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>${groupId}</groupId>
+                            <artifactId>my-lib</artifactId>
+                            <version>1.0.0</version>
+                        </dependency>
+                        <dependency>
+                            <groupId>com.example</groupId>
+                            <artifactId>${artifactId}-core</artifactId>
+                            <version>1.0.0</version>
+                        </dependency>
+                    </dependencies>
+                </project>
+                """;
+
+            Document document = Document.of(pomXml);
+            Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document);
+
+            UpgradeContext context = createMockContext();
+            UpgradeResult result = strategy.doApply(context, pomMap);
+
+            assertTrue(result.success(), "Compatibility fix should succeed");
+            assertTrue(result.modifiedCount() > 0, "Should have fixed deprecated expressions");
+
+            String xml = DomUtils.toXml(document);
+            assertFalse(xml.contains("${groupId}"), "Should not contain deprecated ${groupId}");
+            assertFalse(xml.contains("${artifactId}"), "Should not contain deprecated ${artifactId}");
+            assertTrue(xml.contains("${project.groupId}"), "Should contain ${project.groupId}");
+            assertTrue(xml.contains("${project.artifactId}"), "Should contain ${project.artifactId}");
+        }
+
+        @Test
+        @DisplayName("should replace all three deprecated expressions in one POM")
+        void shouldReplaceAllThreeDeprecatedExpressions() throws Exception {
+            String pomXml = """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <project xmlns="http://maven.apache.org/POM/4.0.0">
+                    <modelVersion>4.0.0</modelVersion>
+                    <groupId>com.example</groupId>
+                    <artifactId>my-project</artifactId>
+                    <version>2.0.0</version>
+                    <properties>
+                        <selfCoords>${groupId}:${artifactId}:${version}</selfCoords>
+                    </properties>
+                </project>
+                """;
+
+            Document document = Document.of(pomXml);
+            Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document);
+
+            UpgradeContext context = createMockContext();
+            UpgradeResult result = strategy.doApply(context, pomMap);
+
+            assertTrue(result.success(), "Compatibility fix should succeed");
+            assertTrue(result.modifiedCount() > 0, "Should have fixed deprecated expressions");
+
+            String xml = DomUtils.toXml(document);
+            assertFalse(xml.contains("${version}"), "Should not contain ${version}");
+            assertFalse(xml.contains("${groupId}"), "Should not contain ${groupId}");
+            assertFalse(xml.contains("${artifactId}"), "Should not contain ${artifactId}");
+            assertTrue(xml.contains("${project.version}"), "Should contain ${project.version}");
+            assertTrue(xml.contains("${project.groupId}"), "Should contain ${project.groupId}");
+            assertTrue(xml.contains("${project.artifactId}"), "Should contain ${project.artifactId}");
+        }
+
+        @Test
+        @DisplayName("should not modify POMs without deprecated expressions")
+        void shouldNotModifyPomsWithoutDeprecatedExpressions() throws Exception {
+            String pomXml = """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <project xmlns="http://maven.apache.org/POM/4.0.0">
+                    <modelVersion>4.0.0</modelVersion>
+                    <groupId>com.example</groupId>
+                    <artifactId>my-project</artifactId>
+                    <version>1.0.0</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>com.example</groupId>
+                            <artifactId>my-lib</artifactId>
+                            <version>${project.version}</version>
+                        </dependency>
+                    </dependencies>
+                </project>
+                """;
+
+            Document document = Document.of(pomXml);
+            Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document);
+
+            UpgradeContext context = createMockContext();
+            UpgradeResult result = strategy.doApply(context, pomMap);
+
+            assertTrue(result.success(), "Compatibility fix should succeed");
+            assertEquals(0, result.modifiedCount(), "Should not have modified POM without deprecated expressions");
+        }
+
+        @Test
+        @DisplayName("should replace deprecated expressions in plugin configuration")
+        void shouldReplaceDeprecatedExpressionsInPluginConfiguration() throws Exception {
+            String pomXml = """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <project xmlns="http://maven.apache.org/POM/4.0.0">
+                    <modelVersion>4.0.0</modelVersion>
+                    <groupId>com.example</groupId>
+                    <artifactId>my-project</artifactId>
+                    <version>1.0.0</version>
+                    <build>
+                        <plugins>
+                            <plugin>
+                                <groupId>org.apache.maven.plugins</groupId>
+                                <artifactId>maven-jar-plugin</artifactId>
+                                <configuration>
+                                    <archive>
+                                        <manifestEntries>
+                                            <Implementation-Version>${version}</Implementation-Version>
+                                        </manifestEntries>
+                                    </archive>
+                                </configuration>
+                            </plugin>
+                        </plugins>
+                    </build>
+                </project>
+                """;
+
+            Document document = Document.of(pomXml);
+            Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document);
+
+            UpgradeContext context = createMockContext();
+            UpgradeResult result = strategy.doApply(context, pomMap);
+
+            assertTrue(result.success(), "Compatibility fix should succeed");
+            assertTrue(result.modifiedCount() > 0, "Should have fixed deprecated ${version} in plugin config");
+
+            String xml = DomUtils.toXml(document);
+            assertFalse(xml.contains("${version}"), "Should not contain deprecated ${version}");
+            assertTrue(xml.contains("${project.version}"), "Should contain ${project.version}");
+        }
+    }
+
     @Nested
     @DisplayName("Strategy Description")
     class StrategyDescriptionTests {