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/09/02 06:55:08 UTC

(maven) 01/02: [MNG-8708] Fix Maven 4 parent inference

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

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

commit 02701fee2dfcbdc0d57982a604de159521077be0
Author: goutamadwant <wo...@gmail.com>
AuthorDate: Fri Aug 7 22:32:45 2026 -0700

    [MNG-8708] Fix Maven 4 parent inference
    
    Distinguish explicitly declared parent coordinates from values inferred through relativePath. Infer an omitted parent version from the matching reactor model before raw-model validation.
    
    Signed-off-by: goutamadwant <wo...@gmail.com>
---
 .../maven/impl/model/DefaultModelBuilder.java      | 37 +++++++++++++-
 .../maven/impl/model/DefaultModelValidator.java    |  4 +-
 .../it/MavenITmng8708ParentInferenceTest.java      | 56 ++++++++++++++++++++++
 .../explicit-both/modules/child/pom.xml            | 10 ++++
 .../explicit-both/pom.xml                          | 11 +++++
 .../supported/modules/gav-only/pom.xml             |  9 ++++
 .../supported/modules/path-only/pom.xml            |  8 ++++
 .../mng-8708-parent-inference/supported/pom.xml    | 12 +++++
 8 files changed, 142 insertions(+), 5 deletions(-)

diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
index 88d0c31b08..0a3caeae09 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
@@ -694,9 +694,11 @@ public void mergeRepositories(Model model, boolean replace) {
 
         //
         // Transform raw model to build pom.
-        // Infer inner reactor dependencies version
+        // Infer missing coordinates from models in the reactor
         //
         Model transformFileToRaw(Model model) {
+            Parent newParent = inferParentVersion(model);
+
             List<Dependency> newDeps = null;
             boolean depsChanged = false;
             if (!model.getDependencies().isEmpty()) {
@@ -712,10 +714,13 @@ Model transformFileToRaw(Model model) {
                 managedDepsChanged = inferDependencies(model, depMgmt.getDependencies(), newManagedDeps);
             }
 
-            if (!depsChanged && !managedDepsChanged) {
+            if (newParent == null && !depsChanged && !managedDepsChanged) {
                 return model;
             }
             Model.Builder builder = Model.newBuilder(model);
+            if (newParent != null) {
+                builder.parent(newParent);
+            }
             if (depsChanged) {
                 builder.dependencies(newDeps);
             }
@@ -725,6 +730,34 @@ Model transformFileToRaw(Model model) {
             return builder.build();
         }
 
+        private Parent inferParentVersion(Model model) {
+            Parent parent = model.getParent();
+            if (parent == null
+                    || parent.getVersion() != null
+                    || parent.getGroupId() == null
+                    || parent.getArtifactId() == null) {
+                return null;
+            }
+
+            Model parentModel = getRawModel(model.getPomFile(), parent.getGroupId(), parent.getArtifactId());
+            if (parentModel == null) {
+                return null;
+            }
+
+            String version = parentModel.getVersion();
+            InputLocation versionLocation = parentModel.getLocation("version");
+            if (version == null && parentModel.getParent() != null) {
+                version = parentModel.getParent().getVersion();
+                versionLocation = parentModel.getParent().getLocation("version");
+            }
+            return version != null
+                    ? parent.with()
+                            .version(version)
+                            .location("version", versionLocation)
+                            .build()
+                    : null;
+        }
+
         /**
          * Infers the missing version or groupId of the given dependencies by looking them up in the reactor.
          * Each dependency, either the original one or the inferred one, is added to {@code result}.
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
index b1a805ce64..292c51b145 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
@@ -339,9 +339,7 @@ public void validateFileModel(Session s, Model m, int validationLevel, ModelProb
 
             if (parent.getRelativePath() != null
                     && !parent.getRelativePath().isEmpty()
-                    && (parent.getGroupId() != null && !parent.getGroupId().isEmpty()
-                            || parent.getArtifactId() != null
-                                    && !parent.getArtifactId().isEmpty())
+                    && (parent.getLocation("groupId") != null || parent.getLocation("artifactId") != null)
                     && validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_4_0
                     && ModelBuilder.KNOWN_MODEL_VERSIONS.contains(m.getModelVersion())
                     && !Objects.equals(m.getModelVersion(), ModelBuilder.MODEL_VERSION_4_0_0)) {
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8708ParentInferenceTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8708ParentInferenceTest.java
new file mode 100644
index 0000000000..2a5c87da4b
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8708ParentInferenceTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.it;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * This is a test set for <a href="https://issues.apache.org/jira/browse/MNG-8708">MNG-8708</a>.
+ *
+ * @since 4.1.0
+ */
+class MavenITmng8708ParentInferenceTest extends AbstractMavenIntegrationTestCase {
+
+    private static final String PARENT_DECLARATION_WARNING =
+            "'parent.relativePath' only specify relativePath or groupId/artifactId in modelVersion 4.1.0";
+
+    @Test
+    void testSupportedParentInference() throws Exception {
+        Path testDir = extractResources("mng-8708-parent-inference/supported");
+
+        Verifier verifier = newVerifier(testDir);
+        verifier.addCliArgument("validate");
+        verifier.execute();
+        verifier.verifyErrorFreeLog();
+        verifier.verifyTextNotInLog(PARENT_DECLARATION_WARNING);
+    }
+
+    @Test
+    void testExplicitPathAndCoordinatesStillWarn() throws Exception {
+        Path testDir = extractResources("mng-8708-parent-inference/explicit-both");
+
+        Verifier verifier = newVerifier(testDir);
+        verifier.addCliArgument("validate");
+        verifier.execute();
+        verifier.verifyErrorFreeLog();
+        verifier.verifyTextInLog(PARENT_DECLARATION_WARNING);
+    }
+}
diff --git a/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/modules/child/pom.xml b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/modules/child/pom.xml
new file mode 100644
index 0000000000..3ca85d2e25
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/modules/child/pom.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <groupId>org.apache.maven.its.mng8708</groupId>
+    <artifactId>parent</artifactId>
+    <relativePath>../..</relativePath>
+  </parent>
+
+  <artifactId>child</artifactId>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/pom.xml b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/pom.xml
new file mode 100644
index 0000000000..b9acadfb5d
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/explicit-both/pom.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0" root="true">
+  <groupId>org.apache.maven.its.mng8708</groupId>
+  <artifactId>parent</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <subprojects>
+    <subproject>modules/child</subproject>
+  </subprojects>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/gav-only/pom.xml b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/gav-only/pom.xml
new file mode 100644
index 0000000000..2647321e95
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/gav-only/pom.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <groupId>org.apache.maven.its.mng8708</groupId>
+    <artifactId>parent</artifactId>
+  </parent>
+
+  <artifactId>gav-only</artifactId>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/path-only/pom.xml b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/path-only/pom.xml
new file mode 100644
index 0000000000..8a9d79925e
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/modules/path-only/pom.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <relativePath>../..</relativePath>
+  </parent>
+
+  <artifactId>path-only</artifactId>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/pom.xml b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/pom.xml
new file mode 100644
index 0000000000..879efe076e
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8708-parent-inference/supported/pom.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0" root="true">
+  <groupId>org.apache.maven.its.mng8708</groupId>
+  <artifactId>parent</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <subprojects>
+    <subproject>modules/path-only</subproject>
+    <subproject>modules/gav-only</subproject>
+  </subprojects>
+</project>