This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new 78ed4a251a Consumer POM of multi-module project should exclude <build>
and <dependencies> elements (#11639)
78ed4a251a is described below
commit 78ed4a251a86273e4ccd0638643b0787359f259a
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Mar 4 20:49:40 2026 +0100
Consumer POM of multi-module project should exclude <build> and
<dependencies> elements (#11639)
* Move some of the codes needed by `ProjectSourcesHelper` in an utility
class that we can reuse in other packages.
* Consumer POM of multi-module project should exclude <build> and
<dependencies> elements.
* Add a test that verifies that `<build>` is preserved when
`preserveModelVersion=true`.
Co-authored-by: Gerd Aschemann <[email protected]>
---
.../impl/ConsumerPomArtifactTransformer.java | 2 +-
.../impl/DefaultConsumerPomBuilder.java | 26 ++++-
.../maven/project/DefaultProjectBuilder.java | 38 +------
.../maven/project/SourceHandlingContext.java | 116 ++++++++++++---------
.../org/apache/maven/project/SourceQueries.java | 84 +++++++++++++++
.../impl/ConsumerPomBuilderTest.java | 86 +++++++++++----
.../test/resources/consumer/multi-module/pom.xml | 41 ++++++++
7 files changed, 281 insertions(+), 112 deletions(-)
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 9444f972a9..f32c962886 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
@@ -96,7 +96,7 @@ public void
injectTransformedArtifacts(RepositorySystemSession session, MavenPro
}
}
- TransformedArtifact createConsumerPomArtifact(
+ private TransformedArtifact createConsumerPomArtifact(
MavenProject project, Path consumer, RepositorySystemSession
session) {
Path actual = project.getFile().toPath();
Path parent = project.getBaseDirectory();
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 c46d3d5b6d..d631e8fd7e 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
@@ -37,6 +37,7 @@
import org.apache.maven.api.model.DistributionManagement;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Parent;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.model.Repository;
import org.apache.maven.api.model.Scm;
@@ -50,6 +51,7 @@
import org.apache.maven.impl.InternalSession;
import org.apache.maven.model.v4.MavenModelVersion;
import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.SourceQueries;
import org.eclipse.aether.RepositorySystemSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -342,7 +344,7 @@ static Model transformNonPom(Model model, MavenProject
project) {
return model;
}
- static Model transformBom(Model model, MavenProject project) {
+ private static Model transformBom(Model model, MavenProject project) {
boolean preserveModelVersion = model.isPreserveModelVersion();
Model.Builder builder = prune(
@@ -369,11 +371,25 @@ static Model transformPom(Model model, MavenProject
project) {
// raw to consumer transform
model = model.withRoot(false).withModules(null).withSubprojects(null);
- if (model.getParent() != null) {
- model = model.withParent(model.getParent().withRelativePath(null));
+ Parent parent = model.getParent();
+ if (parent != null) {
+ model = model.withParent(parent.withRelativePath(null));
+ }
+ var projectSources = project.getBuild().getDelegate().getSources();
+ if (SourceQueries.usesModuleSourceHierarchy(projectSources)) {
+ // Dependencies are dispatched by maven-jar-plugin in the POM
generated for each module.
+ model = model.withDependencies(null).withPackaging(POM_PACKAGING);
}
-
if (!preserveModelVersion) {
+ /*
+ * If the <build> contains <source> elements, it is not compatible
with the Maven 4.0.0 model.
+ * Remove the full <build> element instead of removing only the
<sources> element, because the
+ * build without sources does not mean much. Reminder: this
removal can be disabled by setting
+ * the `preserveModelVersion` XML attribute or
`preserve.model.version` property to true.
+ */
+ if (SourceQueries.hasEnabledSources(projectSources)) {
+ model = model.withBuild(null);
+ }
model = model.withPreserveModelVersion(false);
String modelVersion = new
MavenModelVersion().getModelVersion(model);
model = model.withModelVersion(modelVersion);
@@ -381,7 +397,7 @@ static Model transformPom(Model model, MavenProject
project) {
return model;
}
- static void warnNotDowngraded(MavenProject project) {
+ private static void warnNotDowngraded(MavenProject project) {
LOGGER.warn("The consumer POM for " + project.getId() + " cannot be
downgraded to 4.0.0. "
+ "If you intent your build to be consumed with Maven 3
projects, you need to remove "
+ "the features that request a newer model version. If you're
fine with having the "
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index 7b13a9c12a..cdddbdaafe 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -655,7 +655,6 @@ private void initProject(MavenProject project,
ModelBuilderResult result) {
// only set those on 2nd phase, ignore on 1st pass
if (project.getFile() != null) {
Build build = project.getBuild().getDelegate();
- List<org.apache.maven.api.model.Source> sources =
build.getSources();
Path baseDir = project.getBaseDirectory();
Function<ProjectScope, String> outputDirectory = (scope) -> {
if (scope == ProjectScope.MAIN) {
@@ -666,23 +665,11 @@ private void initProject(MavenProject project,
ModelBuilderResult result) {
return build.getDirectory();
}
};
- // Extract modules from sources to detect modular projects
- Set<String> modules = extractModules(sources);
- boolean isModularProject = !modules.isEmpty();
-
- logger.trace(
- "Module detection for project {}: found {} module(s)
{} - modular project: {}.",
- project.getId(),
- modules.size(),
- modules,
- isModularProject);
-
// Create source handling context for unified tracking of all
lang/scope combinations
- SourceHandlingContext sourceContext =
- new SourceHandlingContext(project, baseDir, modules,
isModularProject, result);
+ final SourceHandlingContext sourceContext = new
SourceHandlingContext(project, result);
// Process all sources, tracking enabled ones and detecting
duplicates
- for (var source : sources) {
+ for (org.apache.maven.api.model.Source source :
sourceContext.sources) {
var sourceRoot = DefaultSourceRoot.fromModel(session,
baseDir, outputDirectory, source);
// Track enabled sources for duplicate detection and
hasSources() queries
// Only add source if it's not a duplicate enabled source
(first enabled wins)
@@ -711,7 +698,7 @@ private void initProject(MavenProject project,
ModelBuilderResult result) {
implicit fallback (only if they match the default,
e.g., inherited)
- This allows incremental adoption (e.g., custom
resources + default Java)
*/
- if (sources.isEmpty()) {
+ if (sourceContext.sources.isEmpty()) {
// Classic fallback: no <sources> configured, use legacy
directories
project.addScriptSourceRoot(build.getScriptSourceDirectory());
project.addCompileSourceRoot(build.getSourceDirectory());
@@ -724,8 +711,7 @@ implicit fallback (only if they match the default, e.g.,
inherited)
if (!sourceContext.hasSources(Language.SCRIPT,
ProjectScope.MAIN)) {
project.addScriptSourceRoot(build.getScriptSourceDirectory());
}
-
- if (isModularProject) {
+ if (sourceContext.usesModuleSourceHierarchy()) {
// Modular: reject ALL legacy directory configurations
failIfLegacyDirectoryPresent(
build.getSourceDirectory(),
@@ -1243,22 +1229,6 @@ public Set<Entry<K, V>> entrySet() {
}
}
- /**
- * Extracts unique module names from the given list of source elements.
- * A project is considered modular if it has at least one module name.
- *
- * @param sources list of source elements from the build
- * @return set of non-blank module names
- */
- private static Set<String>
extractModules(List<org.apache.maven.api.model.Source> sources) {
- return sources.stream()
- .map(org.apache.maven.api.model.Source::getModule)
- .filter(Objects::nonNull)
- .map(String::trim)
- .filter(s -> !s.isBlank())
- .collect(Collectors.toSet());
- }
-
private Model injectLifecycleBindings(
Model model,
ModelBuilderRequest request,
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/project/SourceHandlingContext.java
b/impl/maven-core/src/main/java/org/apache/maven/project/SourceHandlingContext.java
index 400f9f5dc0..1d7eb393e6 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/project/SourceHandlingContext.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/project/SourceHandlingContext.java
@@ -27,6 +27,7 @@
import org.apache.maven.api.ProjectScope;
import org.apache.maven.api.SourceRoot;
import org.apache.maven.api.model.Resource;
+import org.apache.maven.api.model.Source;
import org.apache.maven.api.services.BuilderProblem.Severity;
import org.apache.maven.api.services.ModelBuilderResult;
import org.apache.maven.api.services.ModelProblem.Version;
@@ -37,9 +38,7 @@
/**
* Handles source configuration for Maven projects with unified tracking for
all language/scope combinations.
- * <p>
- * This class replaces the previous approach of hardcoded boolean flags
(hasMain, hasTest, etc.)
- * with a flexible set-based tracking mechanism that works for any language
and scope combination.
+ * This class uses a flexible set-based tracking mechanism that works for any
language and scope combination.
* <p>
* Key features:
* <ul>
@@ -51,7 +50,7 @@
*
* @since 4.0.0
*/
-class SourceHandlingContext {
+final class SourceHandlingContext {
private static final Logger LOGGER =
LoggerFactory.getLogger(SourceHandlingContext.class);
@@ -60,26 +59,38 @@ class SourceHandlingContext {
*/
record SourceKey(Language language, ProjectScope scope, String module,
Path directory) {}
+ /**
+ * The {@code <source>} elements declared in the {@code <build>} elements.
+ */
+ final List<Source> sources;
+
private final MavenProject project;
- private final Path baseDir;
private final Set<String> modules;
- private final boolean modularProject;
private final ModelBuilderResult result;
private final Set<SourceKey> declaredSources;
- SourceHandlingContext(
- MavenProject project,
- Path baseDir,
- Set<String> modules,
- boolean modularProject,
- ModelBuilderResult result) {
+ SourceHandlingContext(MavenProject project, ModelBuilderResult result) {
this.project = project;
- this.baseDir = baseDir;
- this.modules = modules;
- this.modularProject = modularProject;
+ this.sources = project.getBuild().getDelegate().getSources();
+ this.modules = SourceQueries.getModuleNames(sources);
this.result = result;
// Each module typically has main, test, main resources, test
resources = 4 sources
this.declaredSources = new HashSet<>(4 * modules.size());
+ if (usesModuleSourceHierarchy()) {
+ LOGGER.trace("Found {} module(s) in the \"{}\" project: {}.",
project.getId(), modules.size(), modules);
+ } else {
+ LOGGER.trace("Project \"{}\" is non-modular.", project.getId());
+ }
+ }
+
+ /**
+ * Whether the project uses module source hierarchy.
+ * Note that this is not synonymous of whether the project is modular,
+ * because it is possible to create a single Java module in a classic
Maven project
+ * (i.e., using package hierarchy).
+ */
+ boolean usesModuleSourceHierarchy() {
+ return !modules.isEmpty();
}
/**
@@ -112,7 +123,7 @@ boolean shouldAddSource(SourceRoot sourceRoot) {
SourceKey key = new SourceKey(
sourceRoot.language(), sourceRoot.scope(),
sourceRoot.module().orElse(null), normalizedDir);
- if (declaredSources.contains(key)) {
+ if (!declaredSources.add(key)) {
String message = String.format(
"Duplicate enabled source detected: lang=%s, scope=%s,
module=%s, directory=%s. "
+ "First enabled source wins, this duplicate is
ignored.",
@@ -130,7 +141,6 @@ boolean shouldAddSource(SourceRoot sourceRoot) {
return false; // Don't add duplicate enabled source
}
- declaredSources.add(key);
LOGGER.debug(
"Adding and tracking enabled source: lang={}, scope={},
module={}, dir={}",
key.language(),
@@ -151,6 +161,13 @@ boolean hasSources(Language language, ProjectScope scope) {
return declaredSources.stream().anyMatch(key ->
language.equals(key.language()) && scope.equals(key.scope()));
}
+ /**
+ * {@return the source directory as defined by Maven conventions}
+ */
+ private Path getStandardSourceDirectory() {
+ return project.getBaseDirectory().resolve("src");
+ }
+
/**
* Fails the build if modular and classic (non-modular) sources are mixed
within {@code <sources>}.
* <p>
@@ -164,30 +181,32 @@ boolean hasSources(Language language, ProjectScope scope)
{
void failIfMixedModularAndClassicSources() {
for (ProjectScope scope : List.of(ProjectScope.MAIN,
ProjectScope.TEST)) {
for (Language language : List.of(Language.JAVA_FAMILY,
Language.RESOURCES)) {
- boolean hasModular = declaredSources.stream()
- .anyMatch(key ->
- language.equals(key.language()) &&
scope.equals(key.scope()) && key.module() != null);
- boolean hasClassic = declaredSources.stream()
- .anyMatch(key ->
- language.equals(key.language()) &&
scope.equals(key.scope()) && key.module() == null);
-
- if (hasModular && hasClassic) {
- String message = String.format(
- "Mixed modular and classic sources detected for
lang=%s, scope=%s. "
- + "A project must be either fully modular
(all sources have a module) "
- + "or fully classic (no sources have a
module). "
- + "The compiler plugin cannot handle mixed
configurations.",
- language.id(), scope.id());
- LOGGER.error(message);
- result.getProblemCollector()
- .reportProblem(new DefaultModelProblem(
- message,
- Severity.ERROR,
- Version.V41,
- project.getModel().getDelegate(),
- -1,
- -1,
- null));
+ boolean hasModular = false;
+ boolean hasClassic = false;
+ for (SourceKey key : declaredSources) {
+ if (language.equals(key.language()) &&
scope.equals(key.scope())) {
+ String module = key.module();
+ hasModular |= (module != null);
+ hasClassic |= (module == null);
+ if (hasModular && hasClassic) {
+ String message = String.format(
+ "Mixed modular and classic sources
detected for lang=%s, scope=%s. "
+ + "A project must be either fully
modular (all sources have a module) "
+ + "or fully classic (no sources
have a module).",
+ language.id(), scope.id());
+ LOGGER.error(message);
+ result.getProblemCollector()
+ .reportProblem(new DefaultModelProblem(
+ message,
+ Severity.ERROR,
+ Version.V41,
+ project.getModel().getDelegate(),
+ -1,
+ -1,
+ null));
+ break;
+ }
+ }
}
}
}
@@ -219,7 +238,7 @@ void handleResourceConfiguration(ProjectScope scope) {
? "<source><lang>resources</lang></source>"
: "<source><lang>resources</lang><scope>test</scope></source>";
- if (modularProject) {
+ if (usesModuleSourceHierarchy()) {
if (hasResourcesInSources) {
// Modular project with resources configured via <sources> -
already added above
if (hasExplicitLegacyResources(resources, scopeId)) {
@@ -298,6 +317,7 @@ void handleResourceConfiguration(ProjectScope scope) {
// Use legacy resources element
LOGGER.debug(
"Using explicit or default {} resources ({} resources
configured).", scopeId, resources.size());
+ Path baseDir = project.getBaseDirectory();
for (Resource resource : resources) {
project.addSourceRoot(new DefaultSourceRoot(baseDir,
scope, resource));
}
@@ -315,7 +335,7 @@ void handleResourceConfiguration(ProjectScope scope) {
*/
private DefaultSourceRoot createModularResourceRoot(String module,
ProjectScope scope) {
Path resourceDir =
-
baseDir.resolve("src").resolve(module).resolve(scope.id()).resolve("resources");
+
getStandardSourceDirectory().resolve(module).resolve(scope.id()).resolve("resources");
return new DefaultSourceRoot(
scope,
@@ -345,12 +365,10 @@ private boolean hasExplicitLegacyResources(List<Resource>
resources, String scop
}
// Super POM default paths
- String defaultPath =
-
baseDir.resolve("src").resolve(scope).resolve("resources").toString();
- String defaultFilteredPath = baseDir.resolve("src")
- .resolve(scope)
- .resolve("resources-filtered")
- .toString();
+ Path srcDir = getStandardSourceDirectory();
+ String defaultPath =
srcDir.resolve(scope).resolve("resources").toString();
+ String defaultFilteredPath =
+ srcDir.resolve(scope).resolve("resources-filtered").toString();
// Check if any resource differs from Super POM defaults
for (Resource resource : resources) {
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/project/SourceQueries.java
b/impl/maven-core/src/main/java/org/apache/maven/project/SourceQueries.java
new file mode 100644
index 0000000000..41759d1049
--- /dev/null
+++ b/impl/maven-core/src/main/java/org/apache/maven/project/SourceQueries.java
@@ -0,0 +1,84 @@
+/*
+ * 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.project;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.maven.api.model.Source;
+
+/**
+ * Static utility methods for analyzing {@code <source>} elements of a project.
+ * <p>
+ * <strong>Warning:</strong> This is an internal utility class, not part of
the public API.
+ * It can be changed or removed without prior notice.
+ *
+ * @since 4.0.0
+ */
+public final class SourceQueries {
+ private SourceQueries() {}
+
+ /**
+ * Returns whether at least one source in the collection has a non-blank
module name,
+ * indicating a modular source hierarchy.
+ *
+ * @param sources the source elements to check
+ * @return {@code true} if at least one source declares a module
+ */
+ public static boolean usesModuleSourceHierarchy(Collection<Source>
sources) {
+ return
sources.stream().map(Source::getModule).filter(Objects::nonNull).anyMatch(s ->
!s.isBlank());
+ }
+
+ /**
+ * Returns whether at least one source in the collection is enabled.
+ *
+ * @param sources the source elements to check
+ * @return {@code true} if at least one source is enabled
+ */
+ public static boolean hasEnabledSources(Collection<Source> sources) {
+ for (Source source : sources) {
+ if (source.isEnabled()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Extracts unique, non-blank module names from the source elements,
preserving declaration order.
+ * The following relationship should always be true:
+ *
+ * <pre>getModuleNames(sources).isEmpty() ==
!usesModuleSourceHierarchy(sources)</pre>
+ *
+ * @param sources the source elements to extract module names from
+ * @return set of non-blank module names in declaration order
+ */
+ public static Set<String> getModuleNames(Collection<Source> sources) {
+ var modules = new LinkedHashSet<String>();
+ sources.stream()
+ .map(Source::getModule)
+ .filter(Objects::nonNull)
+ .map(String::strip)
+ .filter(s -> !s.isEmpty())
+ .forEach(modules::add);
+ return modules;
+ }
+}
diff --git
a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
index 11dc8cd9c7..d9744cad5f 100644
---
a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
+++
b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
@@ -51,6 +51,7 @@
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -88,15 +89,22 @@ protected List<Object> getSessionServices() {
return services;
}
- @Test
- void testTrivialConsumer() throws Exception {
- InternalMavenSession.from(InternalSession.from(session))
+ /**
+ * Configures {@link #session} with the root directory of a test in {@code
src/test/resources/consumer}.
+ * Returns the request in case the caller wants to apply more
configuration.
+ */
+ private MavenExecutionRequest setRootDirectory(String test) {
+ MavenExecutionRequest request =
InternalMavenSession.from(InternalSession.from(session))
.getMavenSession()
- .getRequest()
-
.setRootDirectory(Paths.get("src/test/resources/consumer/trivial"));
-
- Path file =
Paths.get("src/test/resources/consumer/trivial/child/pom.xml");
+ .getRequest();
+ request.setRootDirectory(Paths.get("src/test/resources/consumer",
test));
+ return request;
+ }
+ /**
+ * Builds the effective model for the given {@code pom.xml} file.
+ */
+ private MavenProject getEffectiveModel(Path file) {
ModelBuilder.ModelBuilderSession mbs = modelBuilder.newSession();
InternalSession.from(session).getData().set(SessionData.key(ModelBuilder.ModelBuilderSession.class),
mbs);
Model orgModel = mbs.build(ModelBuilderRequest.builder()
@@ -108,39 +116,71 @@ void testTrivialConsumer() throws Exception {
MavenProject project = new MavenProject(orgModel);
project.setOriginalModel(new org.apache.maven.model.Model(orgModel));
+ return project;
+ }
+
+ @Test
+ void testTrivialConsumer() throws Exception {
+ setRootDirectory("trivial");
+ Path file =
Paths.get("src/test/resources/consumer/trivial/child/pom.xml");
+
+ MavenProject project = getEffectiveModel(file);
Model model = builder.build(session, project,
Sources.buildSource(file));
assertNotNull(model);
+ assertNotNull(model.getDependencies());
}
@Test
void testSimpleConsumer() throws Exception {
- MavenExecutionRequest request =
InternalMavenSession.from(InternalSession.from(session))
- .getMavenSession()
- .getRequest();
-
request.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
+ MavenExecutionRequest request = setRootDirectory("simple");
request.getUserProperties().setProperty("changelist", "MNG6957");
-
Path file =
Paths.get("src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml");
- ModelBuilder.ModelBuilderSession mbs = modelBuilder.newSession();
-
InternalSession.from(session).getData().set(SessionData.key(ModelBuilder.ModelBuilderSession.class),
mbs);
- Model orgModel = mbs.build(ModelBuilderRequest.builder()
- .session(InternalSession.from(session))
- .source(Sources.buildSource(file))
-
.requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
- .build())
- .getEffectiveModel();
-
- MavenProject project = new MavenProject(orgModel);
- project.setOriginalModel(new org.apache.maven.model.Model(orgModel));
+ MavenProject project = getEffectiveModel(file);
request.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
Model model = builder.build(session, project,
Sources.buildSource(file));
assertNotNull(model);
+ assertFalse(model.getDependencies().isEmpty());
assertTrue(model.getProfiles().isEmpty());
}
+ @Test
+ void testMultiModuleConsumer() throws Exception {
+ setRootDirectory("multi-module");
+ Path file =
Paths.get("src/test/resources/consumer/multi-module/pom.xml");
+
+ MavenProject project = getEffectiveModel(file);
+ Model model = builder.build(session, project,
Sources.buildSource(file));
+
+ assertNotNull(model);
+ assertNull(model.getBuild());
+ assertTrue(model.getDependencies().isEmpty());
+
assertFalse(model.getDependencyManagement().getDependencies().isEmpty());
+ }
+
+ /**
+ * Same test as {@link #testMultiModuleConsumer()}, but verifies that
+ * {@code <build>} is preserved when {@code preserveModelVersion=true}.
+ */
+ @Test
+ void testMultiModuleConsumerPreserveModelVersion() throws Exception {
+ setRootDirectory("multi-module");
+ Path file =
Paths.get("src/test/resources/consumer/multi-module/pom.xml");
+
+ MavenProject project = getEffectiveModel(file);
+ Model model = getEffectiveModel(file).getModel().getDelegate();
+ model = Model.newBuilder(model,
true).preserveModelVersion(true).build();
+
+ Model transformed = DefaultConsumerPomBuilder.transformPom(model,
project);
+
+ assertNotNull(transformed);
+ assertNotNull(transformed.getBuild());
+ assertTrue(transformed.getDependencies().isEmpty());
+
assertFalse(transformed.getDependencyManagement().getDependencies().isEmpty());
+ }
+
@Test
void testScmInheritance() throws Exception {
Model model = Model.newBuilder()
diff --git a/impl/maven-core/src/test/resources/consumer/multi-module/pom.xml
b/impl/maven-core/src/test/resources/consumer/multi-module/pom.xml
new file mode 100644
index 0000000000..972e7c9be2
--- /dev/null
+++ b/impl/maven-core/src/test/resources/consumer/multi-module/pom.xml
@@ -0,0 +1,41 @@
+<project root="true" xmlns="http://maven.apache.org/POM/4.1.0">
+ <groupId>org.my.group</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>2.0.9</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.10.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sources>
+ <source>
+ <module>org.foo</module>
+ </source>
+ <source>
+ <module>org.foo.bar</module>
+ </source>
+ </sources>
+ </build>
+
+</project>