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 <[email protected]>
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 <[email protected]>
---
 .../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 {

Reply via email to