diff --git a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index 3c5bcdd0accd..13e766a95758 100644 --- a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -545,4 +545,44 @@ public void testSubprojectDiscovery() throws Exception { MavenProject parent = p1.getArtifactId().equals("parent") ? p1 : p2; assertEquals(List.of("child"), parent.getModel().getDelegate().getSubprojects()); } + + @Test + public void testEmptySubprojectsElementPreventsDiscovery() throws Exception { + File pom = getTestFile("src/test/resources/projects/subprojects-empty/pom.xml"); + ProjectBuildingRequest configuration = newBuildingRequest(); + InternalSession internalSession = InternalSession.from(configuration.getRepositorySession()); + InternalMavenSession mavenSession = InternalMavenSession.from(internalSession); + mavenSession + .getMavenSession() + .getRequest() + .setRootDirectory(pom.toPath().getParent()); + + List results = projectBuilder.build(List.of(pom), true, configuration); + // Should only build the parent project, not discover the child + assertEquals(1, results.size()); + MavenProject parent = results.get(0).getProject(); + assertEquals("parent", parent.getArtifactId()); + // The subprojects list should be empty since we explicitly defined an empty element + assertTrue(parent.getModel().getDelegate().getSubprojects().isEmpty()); + } + + @Test + public void testEmptyModulesElementPreventsDiscovery() throws Exception { + File pom = getTestFile("src/test/resources/projects/modules-empty/pom.xml"); + ProjectBuildingRequest configuration = newBuildingRequest(); + InternalSession internalSession = InternalSession.from(configuration.getRepositorySession()); + InternalMavenSession mavenSession = InternalMavenSession.from(internalSession); + mavenSession + .getMavenSession() + .getRequest() + .setRootDirectory(pom.toPath().getParent()); + + List results = projectBuilder.build(List.of(pom), true, configuration); + // Should only build the parent project, not discover the child + assertEquals(1, results.size()); + MavenProject parent = results.get(0).getProject(); + assertEquals("parent", parent.getArtifactId()); + // The modules list should be empty since we explicitly defined an empty element + assertTrue(parent.getModel().getDelegate().getModules().isEmpty()); + } } diff --git a/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml b/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml new file mode 100644 index 000000000000..022d86535251 --- /dev/null +++ b/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml @@ -0,0 +1,8 @@ + + + modules-empty + parent + + child + jar + diff --git a/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml b/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml new file mode 100644 index 000000000000..b36128e6a522 --- /dev/null +++ b/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml @@ -0,0 +1,7 @@ + + modules-empty + parent + 1 + pom + + diff --git a/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml b/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml new file mode 100644 index 000000000000..1c4f2b77091b --- /dev/null +++ b/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml @@ -0,0 +1,8 @@ + + + subprojects-empty + parent + + child + jar + diff --git a/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml b/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml new file mode 100644 index 000000000000..840c572d1dad --- /dev/null +++ b/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml @@ -0,0 +1,7 @@ + + subprojects-empty + parent + 1 + pom + + 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 95b7fd842ab7..9b17dcb3803f 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 @@ -1393,7 +1393,7 @@ Model doReadFileModel() throws ModelBuilderException { } // subprojects discovery - if (getSubprojects(model).isEmpty() + if (!hasSubprojectsDefined(model) // only discover subprojects if POM > 4.0.0 && !MODEL_VERSION_4_0_0.equals(model.getModelVersion()) // and if packaging is POM (we check type, but the session is not yet available, @@ -1934,6 +1934,20 @@ private static List getSubprojects(Model activated) { return subprojects; } + /** + * Checks if subprojects are explicitly defined in the main model. + * This method distinguishes between: + * 1. No subprojects/modules element present - returns false (should auto-discover) + * 2. Empty subprojects/modules element present - returns true (should NOT auto-discover) + * 3. Non-empty subprojects/modules - returns true (should NOT auto-discover) + */ + @SuppressWarnings("deprecation") + private static boolean hasSubprojectsDefined(Model model) { + // Only consider the main model: profiles do not influence auto-discovery + // Inline the check for explicit elements using location tracking + return model.getLocation("subprojects") != null || model.getLocation("modules") != null; + } + @Override public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException { RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(request.getSession(), request);