diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
index 41733eb08bf3..07fd999b9f8b 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
@@ -66,6 +66,20 @@ public interface XmlReaderRequest {
boolean isAddDefaultEntities();
+ /**
+ * Indicates whether location information (line/column tracking) should be
+ * recorded during parsing. Defaults to {@code true}. Setting this to
+ * {@code false} for imported dependency management POMs avoids allocating
+ * location maps that are never read, significantly reducing memory churn
+ * in large reactors.
+ *
+ * @return {@code true} if location information should be tracked
+ * @since 4.0.0
+ */
+ default boolean isAddLocationInformation() {
+ return true;
+ }
+
interface Transformer {
/**
* Interpolate the value read from the xml document
@@ -95,6 +109,7 @@ class XmlReaderRequestBuilder {
String modelId;
String location;
boolean addDefaultEntities = true;
+ boolean addLocationInformation = true;
public XmlReaderRequestBuilder path(Path path) {
this.path = path;
@@ -146,6 +161,11 @@ public XmlReaderRequestBuilder addDefaultEntities(boolean addDefaultEntities) {
return this;
}
+ public XmlReaderRequestBuilder addLocationInformation(boolean addLocationInformation) {
+ this.addLocationInformation = addLocationInformation;
+ return this;
+ }
+
public XmlReaderRequest build() {
return new DefaultXmlReaderRequest(
path,
@@ -157,7 +177,8 @@ public XmlReaderRequest build() {
strict,
modelId,
location,
- addDefaultEntities);
+ addDefaultEntities,
+ addLocationInformation);
}
private static class DefaultXmlReaderRequest implements XmlReaderRequest {
@@ -171,6 +192,7 @@ private static class DefaultXmlReaderRequest implements XmlReaderRequest {
final String modelId;
final String location;
final boolean addDefaultEntities;
+ final boolean addLocationInformation;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultXmlReaderRequest(
@@ -183,7 +205,8 @@ private static class DefaultXmlReaderRequest implements XmlReaderRequest {
boolean strict,
String modelId,
String location,
- boolean addDefaultEntities) {
+ boolean addDefaultEntities,
+ boolean addLocationInformation) {
this.path = path;
this.rootDirectory = rootDirectory;
this.url = url;
@@ -194,6 +217,7 @@ private static class DefaultXmlReaderRequest implements XmlReaderRequest {
this.modelId = modelId;
this.location = location;
this.addDefaultEntities = addDefaultEntities;
+ this.addLocationInformation = addLocationInformation;
}
@Override
@@ -245,6 +269,11 @@ public String getLocation() {
public boolean isAddDefaultEntities() {
return addDefaultEntities;
}
+
+ @Override
+ public boolean isAddLocationInformation() {
+ return addLocationInformation;
+ }
}
}
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementImporter.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementImporter.java
index cdcb385a7b5d..118ba1ac1dbd 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementImporter.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementImporter.java
@@ -45,4 +45,21 @@ Model importManagement(
List extends DependencyManagement> sources,
ModelBuilderRequest request,
ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant of {@link #importManagement}.
+ *
+ * @since 4.0.0
+ */
+ default void importManagement(
+ Model.Builder builder,
+ List extends DependencyManagement> sources,
+ ModelBuilderRequest request,
+ ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = importManagement(built, sources, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementInjector.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementInjector.java
index fb91b232cf60..fc29dc218e58 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementInjector.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/DependencyManagementInjector.java
@@ -38,4 +38,24 @@ public interface DependencyManagementInjector {
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
Model injectManagement(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant that operates on a {@link Model.Builder} directly,
+ * avoiding an intermediate {@code Model.build()} between pipeline stages.
+ *
+ * The default implementation bridges to {@link #injectManagement(Model, ModelBuilderRequest, ModelProblemCollector)}
+ * by building the model, processing it, and resetting the builder to the result.
+ *
+ * @param builder The model builder to modify in place, must not be {@code null}.
+ * @param request The model building request, must not be {@code null}.
+ * @param problems The container used to collect problems, must not be {@code null}.
+ * @since 4.0.0
+ */
+ default void injectManagement(Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = injectManagement(built, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/InheritanceAssembler.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/InheritanceAssembler.java
index 59b24f370d04..3fdb1d3a6e81 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/InheritanceAssembler.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/InheritanceAssembler.java
@@ -42,4 +42,18 @@ public interface InheritanceAssembler {
*/
Model assembleModelInheritance(
Model child, Model parent, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant that merges parent values into the child builder directly.
+ *
+ * @since 4.0.0
+ */
+ default void assembleModelInheritance(
+ Model.Builder childBuilder, Model parent, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = childBuilder.build();
+ Model result = assembleModelInheritance(built, parent, request, problems);
+ if (result != built) {
+ childBuilder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelInterpolator.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelInterpolator.java
index c24a8a4d7f1e..4d678b21b4d3 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelInterpolator.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelInterpolator.java
@@ -51,4 +51,21 @@ Model interpolateModel(
@Nullable Path projectDir,
@Nonnull ModelBuilderRequest request,
@Nonnull ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant of {@link #interpolateModel}.
+ *
+ * @since 4.0.0
+ */
+ default void interpolateModel(
+ @Nonnull Model.Builder builder,
+ @Nullable Path projectDir,
+ @Nonnull ModelBuilderRequest request,
+ @Nonnull ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = interpolateModel(built, projectDir, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelNormalizer.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelNormalizer.java
index 50225fd417a5..a8b19a4cd9cb 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelNormalizer.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelNormalizer.java
@@ -48,4 +48,31 @@ public interface ModelNormalizer {
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
Model injectDefaultValues(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant of {@link #mergeDuplicates}.
+ *
+ * @since 4.0.0
+ */
+ default void mergeDuplicates(Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = mergeDuplicates(built, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
+
+ /**
+ * Builder-accepting variant of {@link #injectDefaultValues}.
+ *
+ * @since 4.0.0
+ */
+ default void injectDefaultValues(
+ Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = injectDefaultValues(built, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelPathTranslator.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelPathTranslator.java
index c2ec4ce522ac..eee49ecf486e 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelPathTranslator.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelPathTranslator.java
@@ -40,4 +40,17 @@ public interface ModelPathTranslator {
* @since 4.0.0
*/
Model alignToBaseDirectory(Model model, Path basedir, ModelBuilderRequest request);
+
+ /**
+ * Builder-accepting variant of {@link #alignToBaseDirectory}.
+ *
+ * @since 4.0.0
+ */
+ default void alignToBaseDirectory(Model.Builder builder, Path basedir, ModelBuilderRequest request) {
+ Model built = builder.build();
+ Model result = alignToBaseDirectory(built, basedir, request);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelUrlNormalizer.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelUrlNormalizer.java
index a216b99d7a86..f89cf80e9c1c 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelUrlNormalizer.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelUrlNormalizer.java
@@ -36,4 +36,17 @@ public interface ModelUrlNormalizer {
* @param request The model building request that holds further settings, must not be {@code null}.
*/
Model normalize(Model model, ModelBuilderRequest request);
+
+ /**
+ * Builder-accepting variant of {@link #normalize}.
+ *
+ * @since 4.0.0
+ */
+ default void normalize(Model.Builder builder, ModelBuilderRequest request) {
+ Model built = builder.build();
+ Model result = normalize(built, request);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginConfigurationExpander.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginConfigurationExpander.java
index bdd249489df0..a5f15cb111ea 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginConfigurationExpander.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginConfigurationExpander.java
@@ -37,4 +37,18 @@ public interface PluginConfigurationExpander {
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
Model expandPluginConfiguration(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant of {@link #expandPluginConfiguration}.
+ *
+ * @since 4.0.0
+ */
+ default void expandPluginConfiguration(
+ Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = expandPluginConfiguration(built, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginManagementInjector.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginManagementInjector.java
index 36d7f7e19f86..a2e39c63ca40 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginManagementInjector.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/PluginManagementInjector.java
@@ -38,4 +38,17 @@ public interface PluginManagementInjector {
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
Model injectManagement(Model model, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant of {@link #injectManagement}.
+ *
+ * @since 4.0.0
+ */
+ default void injectManagement(Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = injectManagement(built, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ProfileInjector.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ProfileInjector.java
index 7361318f9801..256ecabdbf17 100644
--- a/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ProfileInjector.java
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ProfileInjector.java
@@ -57,4 +57,21 @@ default Model injectProfile(
*/
Model injectProfiles(
Model model, List profiles, ModelBuilderRequest request, ModelProblemCollector problems);
+
+ /**
+ * Builder-accepting variant that injects profile values into the model builder directly.
+ *
+ * @since 4.0.0
+ */
+ default void injectProfiles(
+ Model.Builder builder,
+ List profiles,
+ ModelBuilderRequest request,
+ ModelProblemCollector problems) {
+ Model built = builder.build();
+ Model result = injectProfiles(built, profiles, request, problems);
+ if (result != built) {
+ builder.reset(result);
+ }
+ }
}
diff --git a/compat/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java b/compat/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
index 640579cb8871..b5b785c7cb7f 100644
--- a/compat/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
+++ b/compat/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
@@ -40,6 +40,10 @@ class FileToRawModelMergerTest {
void testOverriddenMergeMethods() {
List methodNames = Stream.of(MavenMerger.class.getDeclaredMethods())
.filter(m -> m.getName().startsWith("merge"))
+ // Exclude *ToBuilder variants and void methods whose first parameter
+ // is a Builder — only the object-returning merge methods need overriding
+ .filter(m -> !m.getName().endsWith("ToBuilder"))
+ .filter(m -> !m.getParameterTypes()[0].getSimpleName().equals("Builder"))
.filter(m -> {
String baseName = m.getName().substring(5 /* merge */);
String entity = baseName.substring(baseName.indexOf('_') + 1);
diff --git a/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 5f20f38e594c..4c2e72e33541 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -157,8 +157,7 @@ private List trimProjectsToRequest(
if (request.getPom() != null) {
result = getProjectsInRequestScope(request, activeProjects);
- List sortedProjects = graph.getSortedProjects();
- result.sort(comparing(sortedProjects::indexOf));
+ result.sort(comparing(buildProjectIndexMap(graph.getSortedProjects())::get));
result = includeAlsoMakeTransitively(result, request, graph);
}
@@ -189,8 +188,7 @@ private List trimSelectedProjects(
result = includeAlsoMakeTransitively(result, request, graph);
// Order the new list in the original order
- List sortedProjects = graph.getSortedProjects();
- result.sort(comparing(sortedProjects::indexOf));
+ result.sort(comparing(buildProjectIndexMap(graph.getSortedProjects())::get));
}
}
@@ -290,13 +288,24 @@ private List includeAlsoMakeTransitively(
result = new ArrayList<>(projectsSet);
// Order the new list in the original order
- List sortedProjects = graph.getSortedProjects();
- result.sort(comparing(sortedProjects::indexOf));
+ result.sort(comparing(buildProjectIndexMap(graph.getSortedProjects())::get));
}
return result;
}
+ /**
+ * Builds a Map from MavenProject to its index in the sorted list, enabling O(1) index lookups
+ * for sorting instead of O(n) ArrayList.indexOf() scans that cause O(n² log n) sort performance.
+ */
+ private static Map buildProjectIndexMap(List sortedProjects) {
+ Map indexMap = new HashMap<>(sortedProjects.size() * 2);
+ for (int i = 0; i < sortedProjects.size(); i++) {
+ indexMap.put(sortedProjects.get(i), i);
+ }
+ return indexMap;
+ }
+
private void enrichRequestFromResumptionData(List projects, MavenExecutionRequest request) {
if (request.isResume()) {
projects.stream()
diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
index 2a1efccfbfbf..575c70ab03c7 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
@@ -19,16 +19,19 @@
package org.apache.maven.lifecycle.internal;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Compares phases within the context of a specific lifecycle with secondary sorting based on the {@link PhaseId}.
*/
public class PhaseComparator implements Comparator {
/**
- * The lifecycle phase ordering.
+ * Map from phase name to its index in the lifecycle, enabling O(1) lookups
+ * instead of O(n) List.indexOf() scans on every comparison.
*/
- private final List lifecyclePhases;
+ private final Map phaseIndexMap;
/**
* Constructor.
@@ -36,24 +39,27 @@ public class PhaseComparator implements Comparator {
* @param lifecyclePhases the lifecycle phase ordering.
*/
public PhaseComparator(List lifecyclePhases) {
- this.lifecyclePhases = lifecyclePhases;
+ this.phaseIndexMap = new HashMap<>(lifecyclePhases.size() * 2);
+ for (int i = 0; i < lifecyclePhases.size(); i++) {
+ phaseIndexMap.put(lifecyclePhases.get(i), i);
+ }
}
@Override
public int compare(String o1, String o2) {
PhaseId p1 = PhaseId.of(o1);
PhaseId p2 = PhaseId.of(o2);
- int i1 = lifecyclePhases.indexOf(p1.executionPoint().prefix() + p1.phase());
- int i2 = lifecyclePhases.indexOf(p2.executionPoint().prefix() + p2.phase());
- if (i1 == -1 && i2 == -1) {
+ Integer i1 = phaseIndexMap.get(p1.executionPoint().prefix() + p1.phase());
+ Integer i2 = phaseIndexMap.get(p2.executionPoint().prefix() + p2.phase());
+ if (i1 == null && i2 == null) {
// unknown phases, leave in existing order
return 0;
}
- if (i1 == -1) {
+ if (i1 == null) {
// second one is known, so it comes first
return 1;
}
- if (i2 == -1) {
+ if (i2 == null) {
// first one is known, so it comes first
return -1;
}
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultModelXmlFactory.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultModelXmlFactory.java
index 575d35e230d8..c87ce5034315 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultModelXmlFactory.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultModelXmlFactory.java
@@ -132,6 +132,7 @@ private Model doRead(XmlReaderRequest request) throws XmlReaderException {
? new MavenStaxReader(request.getTransformer()::transform)
: new MavenStaxReader();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
+ xml.setAddLocationInformation(request.isAddLocationInformation());
if (inputStream != null) {
return xml.read(inputStream, request.isStrict(), source);
} else if (reader != null) {
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultPluginConfigurationExpander.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultPluginConfigurationExpander.java
index fc159b8ccd2a..264d01d35642 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultPluginConfigurationExpander.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultPluginConfigurationExpander.java
@@ -44,6 +44,30 @@
@Singleton
public class DefaultPluginConfigurationExpander implements PluginConfigurationExpander {
+ @Override
+ public void expandPluginConfiguration(
+ Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+
+ // Use builder getters instead of builder.build() to avoid materializing
+ // all model-object lists (especially dependencies) just to read Build/Reporting
+ Build build = builder.getBuild();
+ if (build != null) {
+ Build newBuild = build.withPlugins(expandPlugin(build.getPlugins()));
+ PluginManagement pluginManagement = newBuild.getPluginManagement();
+ if (pluginManagement != null) {
+ newBuild = newBuild.withPluginManagement(
+ pluginManagement.withPlugins(expandPlugin(pluginManagement.getPlugins())));
+ }
+ if (newBuild != build) {
+ builder.build(newBuild);
+ }
+ }
+ Reporting reporting = builder.getReporting();
+ if (reporting != null) {
+ expandReport(reporting.getPlugins());
+ }
+ }
+
@Override
public Model expandPluginConfiguration(Model model, ModelBuilderRequest request, ModelProblemCollector problems) {
Build build = model.getBuild();
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementImporter.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementImporter.java
index 45de07f83a3c..828f8568980c 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementImporter.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementImporter.java
@@ -167,6 +167,8 @@ static Dependency updateWithImportedFrom(Dependency dependency, DependencyManage
if (dependencySource == null
|| bomSource == null
|| Objects.equals(dependencySource.getModelId(), bomSource.getModelId())) {
+ // Use forceCopy=true since we only set importedFrom (no field changes that would
+ // trigger copy-on-write), and build immediately as we need the immutable result.
return Dependency.newBuilder(dependency, true)
.importedFrom(bomLocation)
.build();
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementInjector.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementInjector.java
index d5c7d5d3e1b1..0013bd03c670 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementInjector.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultDependencyManagementInjector.java
@@ -45,6 +45,20 @@ public class DefaultDependencyManagementInjector implements DependencyManagement
private ManagementModelMerger merger = new ManagementModelMerger();
+ @Override
+ public void injectManagement(Model.Builder builder, ModelBuilderRequest request, ModelProblemCollector problems) {
+ // Use builder getters instead of builder.build() to avoid materializing
+ // all model-object lists just to read Dependencies and DependencyManagement
+ DependencyManagement depMgmt = builder.getDependencyManagement();
+ if (depMgmt != null) {
+ List deps = builder.getBuiltDependencies();
+ List merged = merger.computeMergedDependencies(deps, depMgmt);
+ if (merged != null) {
+ builder.dependencies(merged);
+ }
+ }
+ }
+
@Override
public Model injectManagement(Model model, ModelBuilderRequest request, ModelProblemCollector problems) {
return merger.mergeManagedDependencies(model);
@@ -55,41 +69,60 @@ public Model injectManagement(Model model, ModelBuilderRequest request, ModelPro
*/
protected static class ManagementModelMerger extends MavenModelMerger {
- public Model mergeManagedDependencies(Model model) {
+ /**
+ * Computes the merged dependency list, or returns {@code null} if no dependencies were modified.
+ */
+ List computeMergedDependencies(Model model) {
DependencyManagement dependencyManagement = model.getDependencyManagement();
if (dependencyManagement != null) {
- Map