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

gnodet pushed a commit to branch gh-11772-dual-consumer-pom
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 9a6607fca968fe84d39c80e25e2cceb66bdd50ab
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Mar 10 09:24:35 2026 +0100

    [GH-11772] Generate dual consumer POMs for parent POMs with 4.1.0 features
    
    When a POM-packaged project uses model version 4.1.0 features (e.g.,
    profile condition activation, subprojects), the consumer POM cannot be
    downgraded to 4.0.0, breaking Maven 3 and Gradle consumers.
    
    This fix generates dual consumer POMs:
    - Main POM (no classifier): 4.0.0-compatible with 4.1.0 features stripped
    - Consumer POM (classifier): 4.1.0 full-fidelity with parent classifier
    
    Changes:
    - Add classifier field to Parent in maven.mdo (4.1.0+)
    - DefaultConsumerPomBuilder: add stripTo400() and dual POM generation
    - ConsumerPomArtifactTransformer: handle consumer-full artifact lifecycle
    - DefaultModelResolver: pass parent classifier during resolution
    - DefaultModelBuilder: skip local parent resolution when classifier set
    
    Fixes #11772
---
 api/maven-api-model/src/main/mdo/maven.mdo         |  10 ++
 .../impl/ConsumerPomArtifactTransformer.java       |  93 +++++++++++++---
 .../impl/DefaultConsumerPomBuilder.java            | 105 ++++++++++++++++++
 .../internal/transformation/impl/PomBuilder.java   |   8 ++
 .../maven/impl/model/DefaultModelBuilder.java      |   2 +-
 .../maven/impl/resolver/DefaultModelResolver.java  |   2 +-
 .../it/MavenITgh11772DualConsumerPomTest.java      | 122 +++++++++++++++++++++
 .../gh-11772-dual-consumer-pom/child/pom.xml       |  37 +++++++
 .../resources/gh-11772-dual-consumer-pom/pom.xml   |  51 +++++++++
 9 files changed, 415 insertions(+), 15 deletions(-)

diff --git a/api/maven-api-model/src/main/mdo/maven.mdo 
b/api/maven-api-model/src/main/mdo/maven.mdo
index e7acdd78c8..b6cf928433 100644
--- a/api/maven-api-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -1814,6 +1814,16 @@
           </description>
           <type>String</type>
         </field>
+        <field>
+          <name>classifier</name>
+          <version>4.1.0+</version>
+          <description>
+            The classifier of the parent POM to resolve from the repository.
+            This is used by consumer POMs to reference the full-fidelity 
consumer POM
+            of the parent project, which is deployed with a classifier (e.g., 
{@code consumer}).
+          </description>
+          <type>String</type>
+        </field>
       </fields>
       <codeSegments>
         <codeSegment>
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
index adaf72c7ba..531f39898c 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
@@ -32,11 +32,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 import org.apache.maven.api.feature.Features;
-import org.apache.maven.api.model.Model;
 import org.apache.maven.api.services.ModelBuilderException;
 import org.apache.maven.api.services.ModelSource;
 import org.apache.maven.api.services.Source;
@@ -58,11 +59,15 @@
 @Singleton
 @Named
 class ConsumerPomArtifactTransformer extends TransformerSupport {
-    private static final String CONSUMER_POM_CLASSIFIER = "consumer";
+    static final String CONSUMER_POM_CLASSIFIER = "consumer";
+
+    private static final String CONSUMER_POM_FULL_CLASSIFIER = "consumer-full";
 
     private static final String BUILD_POM_CLASSIFIER = "build";
 
     private final Set<Path> toDelete = new CopyOnWriteArraySet<>();
+    private final Map<Path, byte[]> consumerFullCache = new 
ConcurrentHashMap<>();
+    private final Set<Path> consumerFullPaths = ConcurrentHashMap.newKeySet();
 
     private final PomBuilder builder;
 
@@ -89,7 +94,15 @@ public void 
injectTransformedArtifacts(RepositorySystemSession session, MavenPro
                     : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", 
".pom");
             deferDeleteFile(consumer);
 
+            Path consumerFull = buildDir != null
+                    ? Files.createTempFile(buildDir, 
CONSUMER_POM_FULL_CLASSIFIER + "-", ".pom")
+                    : Files.createTempFile(CONSUMER_POM_FULL_CLASSIFIER + "-", 
".pom");
+            deferDeleteFile(consumerFull);
+            consumerFullPaths.add(consumerFull.toAbsolutePath());
+
             project.addAttachedArtifact(createConsumerPomArtifact(project, 
consumer, session));
+            project.addAttachedArtifact(
+                    createConsumerPomArtifact(project, consumerFull, session, 
CONSUMER_POM_FULL_CLASSIFIER));
         } else if (project.getModel().getDelegate().isRoot()) {
             throw new IllegalStateException(
                     "The use of the root attribute on the model requires the 
buildconsumer feature to be active");
@@ -98,6 +111,11 @@ public void 
injectTransformedArtifacts(RepositorySystemSession session, MavenPro
 
     TransformedArtifact createConsumerPomArtifact(
             MavenProject project, Path consumer, RepositorySystemSession 
session) {
+        return createConsumerPomArtifact(project, consumer, session, 
CONSUMER_POM_CLASSIFIER);
+    }
+
+    TransformedArtifact createConsumerPomArtifact(
+            MavenProject project, Path consumer, RepositorySystemSession 
session, String classifier) {
         Path actual = project.getFile().toPath();
         Path parent = project.getBaseDirectory();
         ModelSource source = new ModelSource() {
@@ -133,21 +151,51 @@ public ModelSource resolve(ModelLocator modelLocator, 
String relative) {
             }
         };
         return new TransformedArtifact(
-                this,
-                project,
-                consumer,
-                session,
-                new ProjectArtifact(project),
-                () -> source,
-                CONSUMER_POM_CLASSIFIER,
-                "pom");
+                this, project, consumer, session, new 
ProjectArtifact(project), () -> source, classifier, "pom");
     }
 
     @Override
     public void transform(MavenProject project, RepositorySystemSession 
session, ModelSource src, Path tgt)
             throws ModelBuilderException, XMLStreamException, IOException {
-        Model model = builder.build(session, project, src);
-        write(model, tgt);
+        if (consumerFullPaths.contains(tgt.toAbsolutePath())) {
+            // This is the consumer-full artifact — check if we have cached 
content
+            byte[] cached = consumerFullCache.remove(tgt.toAbsolutePath());
+            if (cached != null) {
+                Files.write(tgt, cached);
+            }
+            // If no cached content, leave the file empty (will be skipped 
during deploy)
+        } else {
+            // This is the main consumer artifact
+            PomBuilder.ConsumerPomBuildResult result = 
builder.buildConsumerPoms(session, project, src);
+            write(result.main(), tgt);
+            if (result.consumer() != null) {
+                // Cache the consumer-full content for later
+                Path consumerFullPath = findConsumerFullPath(tgt);
+                if (consumerFullPath != null) {
+                    java.io.ByteArrayOutputStream baos = new 
java.io.ByteArrayOutputStream();
+                    try (java.io.OutputStream os = baos) {
+                        new 
org.apache.maven.model.v4.MavenStaxWriter().write(os, result.consumer());
+                    }
+                    consumerFullCache.put(consumerFullPath, 
baos.toByteArray());
+                }
+            }
+        }
+    }
+
+    private Path findConsumerFullPath(Path mainPath) {
+        // Find the consumer-full path that's in the same directory as the 
main path
+        Path dir = mainPath.getParent();
+        for (Path p : consumerFullPaths) {
+            if (p.getParent().equals(dir)) {
+                return p;
+            }
+        }
+        return null;
+    }
+
+    boolean hasConsumerFullContent(Path path) {
+        return consumerFullCache.containsKey(path.toAbsolutePath())
+                || (Files.exists(path) && path.toFile().length() > 0);
     }
 
     private void deferDeleteFile(Path generatedFile) {
@@ -188,10 +236,13 @@ private boolean consumerPomPresent(Collection<Artifact> 
artifacts) {
 
     private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
         List<Artifact> consumers = new ArrayList<>();
+        List<Artifact> consumerFulls = new ArrayList<>();
         List<Artifact> mains = new ArrayList<>();
         for (Artifact artifact : artifacts) {
             if ("pom".equals(artifact.getExtension()) || 
artifact.getExtension().startsWith("pom.")) {
-                if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) {
+                if 
(CONSUMER_POM_FULL_CLASSIFIER.equals(artifact.getClassifier())) {
+                    consumerFulls.add(artifact);
+                } else if 
(CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) {
                     consumers.add(artifact);
                 } else if ("".equals(artifact.getClassifier())) {
                     mains.add(artifact);
@@ -200,6 +251,7 @@ private Collection<Artifact> 
replacePom(Collection<Artifact> artifacts) {
         }
         if (!mains.isEmpty() && !consumers.isEmpty()) {
             ArrayList<Artifact> result = new ArrayList<>(artifacts);
+            // original POM → build classifier
             for (Artifact main : mains) {
                 result.remove(main);
                 result.add(new DefaultArtifact(
@@ -211,6 +263,7 @@ private Collection<Artifact> 
replacePom(Collection<Artifact> artifacts) {
                         main.getProperties(),
                         main.getPath()));
             }
+            // consumer POM → main (no classifier)
             for (Artifact consumer : consumers) {
                 result.remove(consumer);
                 result.add(new DefaultArtifact(
@@ -222,6 +275,20 @@ private Collection<Artifact> 
replacePom(Collection<Artifact> artifacts) {
                         consumer.getProperties(),
                         consumer.getPath()));
             }
+            // consumer-full POM → consumer classifier (only if it has content)
+            for (Artifact consumerFull : consumerFulls) {
+                result.remove(consumerFull);
+                if (consumerFull.getPath() != null && 
hasConsumerFullContent(consumerFull.getPath())) {
+                    result.add(new DefaultArtifact(
+                            consumerFull.getGroupId(),
+                            consumerFull.getArtifactId(),
+                            CONSUMER_POM_CLASSIFIER,
+                            consumerFull.getExtension(),
+                            consumerFull.getVersion(),
+                            consumerFull.getProperties(),
+                            consumerFull.getPath()));
+                }
+            }
             artifacts = result;
         }
         return artifacts;
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
index da8f1e1401..eafdf553d6 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
@@ -33,8 +33,11 @@
 import org.apache.maven.api.PathScope;
 import org.apache.maven.api.SessionData;
 import org.apache.maven.api.feature.Features;
+import org.apache.maven.api.model.Activation;
+import org.apache.maven.api.model.Build;
 import org.apache.maven.api.model.Dependency;
 import org.apache.maven.api.model.DistributionManagement;
+import org.apache.maven.api.model.Extension;
 import org.apache.maven.api.model.Model;
 import org.apache.maven.api.model.ModelBase;
 import org.apache.maven.api.model.Profile;
@@ -103,6 +106,47 @@ public Model build(RepositorySystemSession session, 
MavenProject project, ModelS
         }
     }
 
+    @Override
+    public ConsumerPomBuildResult buildConsumerPoms(
+            RepositorySystemSession session, MavenProject project, ModelSource 
src) throws ModelBuilderException {
+        Model model = project.getModel().getDelegate();
+        boolean flattenEnabled = 
Features.consumerPomFlatten(session.getConfigProperties());
+        String packaging = model.getPackaging();
+        String originalPackaging = project.getOriginalModel().getPackaging();
+
+        boolean isBom = BOM_PACKAGING.equals(originalPackaging);
+
+        if (!flattenEnabled) {
+            if (POM_PACKAGING.equals(packaging) && !isBom) {
+                return buildPomConsumerPoms(session, project, src);
+            }
+        } else {
+            if (POM_PACKAGING.equals(packaging) && !isBom) {
+                return buildPomConsumerPoms(session, project, src);
+            }
+        }
+        // For non-POM, BOMs, etc., fall back to single POM
+        return new ConsumerPomBuildResult(build(session, project, src), null);
+    }
+
+    protected ConsumerPomBuildResult buildPomConsumerPoms(
+            RepositorySystemSession session, MavenProject project, ModelSource 
src) throws ModelBuilderException {
+        ModelBuilderResult result = buildModel(session, src);
+        Model rawModel = result.getRawModel();
+        Model consumerModel = transformPom(rawModel, project);
+
+        String modelVersion = consumerModel.getModelVersion();
+        if (ModelBuilder.MODEL_VERSION_4_0_0.equals(modelVersion) || 
consumerModel.isPreserveModelVersion()) {
+            return new ConsumerPomBuildResult(consumerModel, null);
+        }
+
+        // Generate dual consumer POMs: main (4.0.0) + consumer (4.1.0)
+        Model consumer410 = addConsumerClassifierToParent(consumerModel);
+        Model main400 = stripTo400(consumerModel);
+
+        return new ConsumerPomBuildResult(main400, consumer410);
+    }
+
     protected Model buildPom(RepositorySystemSession session, MavenProject 
project, ModelSource src)
             throws ModelBuilderException {
         ModelBuilderResult result = buildModel(session, src);
@@ -380,4 +424,65 @@ private static List<Repository> 
pruneRepositories(List<Repository> repositories)
                 .filter(r -> 
!org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
                 .collect(Collectors.toList());
     }
+
+    static Model stripTo400(Model model) {
+        // Strip profile condition and packaging activation (4.1.0 features)
+        if (!model.getProfiles().isEmpty()) {
+            List<Profile> strippedProfiles = model.getProfiles().stream()
+                    .map(DefaultConsumerPomBuilder::stripProfileTo400)
+                    .collect(Collectors.toList());
+            model = model.withProfiles(strippedProfiles);
+        }
+
+        // Strip build sources (4.1.0 feature)
+        if (model.getBuild() != null) {
+            model = model.withBuild(stripBuildTo400(model.getBuild()));
+        }
+
+        // Strip subprojects (4.1.0 feature, should already be stripped by 
transformPom but be safe)
+        model = model.withSubprojects(null);
+
+        // Force model version to 4.0.0
+        model = model.withModelVersion(ModelBuilder.MODEL_VERSION_4_0_0);
+        model = model.withPreserveModelVersion(false);
+        model = model.withRoot(false);
+
+        return model;
+    }
+
+    private static Profile stripProfileTo400(Profile profile) {
+        if (profile.getActivation() != null) {
+            Activation activation = profile.getActivation();
+            if (activation.getCondition() != null || activation.getPackaging() 
!= null) {
+                activation = Activation.newBuilder(activation, true)
+                        .condition(null)
+                        .packaging(null)
+                        .build();
+                profile = profile.withActivation(activation);
+            }
+        }
+        return profile;
+    }
+
+    private static Build stripBuildTo400(Build build) {
+        // Strip sources (4.1.0 feature)
+        if (!build.getSources().isEmpty()) {
+            build = build.withSources(null);
+        }
+        // Strip extension configuration (4.1.0 feature)
+        if (!build.getExtensions().isEmpty()) {
+            List<Extension> strippedExtensions = build.getExtensions().stream()
+                    .map(ext -> ext.getConfiguration() != null ? 
ext.withConfiguration(null) : ext)
+                    .collect(Collectors.toList());
+            build = build.withExtensions(strippedExtensions);
+        }
+        return build;
+    }
+
+    static Model addConsumerClassifierToParent(Model model) {
+        if (model.getParent() != null) {
+            model = 
model.withParent(model.getParent().withClassifier("consumer"));
+        }
+        return model;
+    }
 }
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java
 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java
index 86f9bed73a..3e2f4179f8 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java
@@ -35,4 +35,12 @@
 interface PomBuilder {
     Model build(RepositorySystemSession session, MavenProject project, 
ModelSource src)
             throws ModelBuilderException, IOException, XMLStreamException;
+
+    default ConsumerPomBuildResult buildConsumerPoms(
+            RepositorySystemSession session, MavenProject project, ModelSource 
src)
+            throws ModelBuilderException, IOException, XMLStreamException {
+        return new ConsumerPomBuildResult(build(session, project, src), null);
+    }
+
+    record ConsumerPomBuildResult(Model main, Model consumer) {}
 }
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 b3356a2208..7fe660a07f 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
@@ -1050,7 +1050,7 @@ private Model resolveParent(
                 Set<String> parentChain)
                 throws ModelBuilderException {
             Model parentModel = null;
-            if (isBuildRequest()) {
+            if (isBuildRequest() && parent.getClassifier() == null) {
                 parentModel = readParentLocally(childModel, parent, 
profileActivationContext, parentChain);
             }
             if (parentModel == null) {
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java
index 03973c981e..1fc1c0fc4c 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java
@@ -68,7 +68,7 @@ public ModelSource resolveModel(
                         parent.getGroupId(),
                         parent.getArtifactId(),
                         parent.getVersion(),
-                        null),
+                        parent.getClassifier()),
                 parent.getLocation("version"),
                 "parent");
         if (result.version() != null) {
diff --git 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java
 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java
new file mode 100644
index 0000000000..90d233f435
--- /dev/null
+++ 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Integration test for <a 
href="https://github.com/apache/maven/issues/11772";>GH-11772</a>.
+ * <p>
+ * Verifies that when a POM-packaged project (parent) uses model version 4.1.0 
features
+ * (like profile condition activation), Maven generates dual consumer POMs:
+ * <ul>
+ *   <li>Main POM (no classifier): 4.0.0-compatible, 4.1.0 features 
stripped</li>
+ *   <li>Consumer classifier POM: 4.1.0 full-fidelity, parent references 
consumer classifier</li>
+ * </ul>
+ */
+class MavenITgh11772DualConsumerPomTest extends 
AbstractMavenIntegrationTestCase {
+
+    MavenITgh11772DualConsumerPomTest() {
+        super("[4.0.0-rc-2,)");
+    }
+
+    private static final String GROUP_ID = "org.apache.maven.its.gh11772";
+
+    @Test
+    void testDualConsumerPomsForParent() throws Exception {
+        Path basedir = 
extractResources("/gh-11772-dual-consumer-pom").toPath();
+
+        Verifier verifier = newVerifier(basedir.toString(), null);
+        verifier.addCliArguments("install");
+        verifier.execute();
+        verifier.verifyErrorFreeLog();
+
+        // Verify parent POM artifacts in project-local-repo
+        Path parentDir = basedir.resolve(Paths.get(
+                "target",
+                "project-local-repo",
+                "org.apache.maven.its.gh11772",
+                "parent",
+                "1.0.0-SNAPSHOT"));
+
+        Path parentMainPom = parentDir.resolve("parent-1.0.0-SNAPSHOT.pom");
+        Path parentConsumerPom = 
parentDir.resolve("parent-1.0.0-SNAPSHOT-consumer.pom");
+        Path parentBuildPom = 
parentDir.resolve("parent-1.0.0-SNAPSHOT-build.pom");
+
+        assertTrue("Parent main POM should exist", 
Files.exists(parentMainPom));
+        assertTrue("Parent consumer POM should exist", 
Files.exists(parentConsumerPom));
+        assertTrue("Parent build POM should exist", 
Files.exists(parentBuildPom));
+
+        // Main POM should be 4.0.0-compatible
+        Model mainModel;
+        try (Reader r = Files.newBufferedReader(parentMainPom)) {
+            mainModel = new MavenStaxReader().read(r);
+        }
+        assertEquals("4.0.0", mainModel.getModelVersion());
+
+        // Main POM should NOT have condition activation (stripped for 4.0.0 
compat)
+        for (var profile : mainModel.getProfiles()) {
+            if (profile.getActivation() != null) {
+                assertNull(
+                        "Main POM profiles should not have condition 
activation",
+                        profile.getActivation().getCondition());
+            }
+        }
+
+        // Consumer POM should be 4.1.0 full-fidelity
+        Model consumerModel;
+        try (Reader r = Files.newBufferedReader(parentConsumerPom)) {
+            consumerModel = new MavenStaxReader().read(r);
+        }
+        assertEquals("4.1.0", consumerModel.getModelVersion());
+
+        // Verify child POM
+        Path childDir = basedir.resolve(Paths.get(
+                "target",
+                "project-local-repo",
+                "org.apache.maven.its.gh11772",
+                "child",
+                "1.0.0-SNAPSHOT"));
+        Path childMainPom = childDir.resolve("child-1.0.0-SNAPSHOT.pom");
+        assertTrue("Child main POM should exist", Files.exists(childMainPom));
+
+        Model childModel;
+        try (Reader r = Files.newBufferedReader(childMainPom)) {
+            childModel = new MavenStaxReader().read(r);
+        }
+        assertNotNull("Child POM should have a parent reference", 
childModel.getParent());
+        assertEquals(GROUP_ID, childModel.getParent().getGroupId());
+        assertEquals("parent", childModel.getParent().getArtifactId());
+        assertNull(
+                "Child POM parent should not have a classifier",
+                childModel.getParent().getClassifier());
+    }
+}
diff --git 
a/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml 
b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml
new file mode 100644
index 0000000000..cf3c44eea2
--- /dev/null
+++ 
b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0";>
+
+  <parent>
+    <groupId>org.apache.maven.its.gh11772</groupId>
+    <artifactId>parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>child</artifactId>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git 
a/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml 
b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml
new file mode 100644
index 0000000000..b227adf992
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0"; root="true">
+
+  <groupId>org.apache.maven.its.gh11772</groupId>
+  <artifactId>parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <subprojects>
+    <subproject>child</subproject>
+  </subprojects>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>2.0.9</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <profiles>
+    <profile>
+      <id>test-profile</id>
+      <activation>
+        <!-- 4.1.0 feature: condition-based activation -->
+        <condition>${project.artifactId} == 'parent'</condition>
+      </activation>
+    </profile>
+  </profiles>
+
+</project>

Reply via email to