diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index f315f64b75..4ff0becbc5 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -167,6 +167,9 @@ under the License.
org.apache.maven.model.profile.activation.FileProfileActivator#setProfileActivationFilePathInterpolator(org.apache.maven.model.path.ProfileActivationFilePathInterpolator):METHOD_REMOVED
org.apache.maven.model.profile.activation.FileProfileActivator#FileProfileActivator():CONSTRUCTOR_REMOVED
org.apache.maven.model.profile.DefaultProfileInjector
+ org.apache.maven.model.profile.ProfileInjector#injectProfile(org.apache.maven.api.model.Model,org.apache.maven.api.model.Profile,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT
+ org.apache.maven.model.profile.ProfileInjector#injectProfiles(org.apache.maven.api.model.Model,java.util.List,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT
+ org.apache.maven.model.profile.ProfileSelector#getActiveProfilesV4(java.util.Collection,org.apache.maven.model.profile.ProfileActivationContext,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT
org.apache.maven.model.resolution.InvalidRepositoryException#getRepository():METHOD_RETURN_TYPE_CHANGED
org.apache.maven.model.resolution.InvalidRepositoryException#InvalidRepositoryException(java.lang.String,org.apache.maven.model.Repository,java.lang.Throwable):CONSTRUCTOR_REMOVED
org.apache.maven.model.resolution.InvalidRepositoryException#InvalidRepositoryException(java.lang.String,org.apache.maven.model.Repository):CONSTRUCTOR_REMOVED
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
index f67ca6275c..a435002837 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
@@ -26,6 +26,8 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.api.model.Build;
import org.apache.maven.api.model.BuildBase;
@@ -34,6 +36,7 @@
import org.apache.maven.api.model.Plugin;
import org.apache.maven.api.model.PluginContainer;
import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.Profile;
import org.apache.maven.api.model.ReportPlugin;
import org.apache.maven.api.model.ReportSet;
import org.apache.maven.api.model.Reporting;
@@ -50,6 +53,13 @@
@SuppressWarnings({"checkstyle:methodname"})
public class DefaultProfileInjector implements ProfileInjector {
+ private static final Map, Model>> CACHE = Collections.synchronizedMap(new WeakHashMap<>());
+
+ // In order for the weak hash map to work correctly, we must not hold any reference to
+ // the model used as the key. So we use a dummy model as a placeholder to indicate that
+ // we want to store the model used as they key.
+ private static final Model KEY = Model.newInstance();
+
private ProfileModelMerger merger = new ProfileModelMerger();
@Override
@@ -58,19 +68,42 @@ public void injectProfile(
org.apache.maven.model.Profile profile,
ModelBuildingRequest request,
ModelProblemCollector problems) {
- if (profile != null) {
- Model.Builder builder = Model.newBuilder(model.getDelegate());
- merger.mergeModelBase(builder, model.getDelegate(), profile.getDelegate());
+ model.update(
+ injectProfile(model.getDelegate(), profile != null ? profile.getDelegate() : null, request, problems));
+ }
- if (profile.getBuild() != null) {
- Build build = model.getBuild() != null ? model.getBuild().getDelegate() : Build.newInstance();
- Build.Builder bbuilder = Build.newBuilder(build);
- merger.mergeBuildBase(bbuilder, build, profile.getBuild().getDelegate());
- builder.build(bbuilder.build());
+ @Override
+ public Model injectProfile(
+ Model model, Profile profile, ModelBuildingRequest request, ModelProblemCollector problems) {
+ return injectProfiles(model, Collections.singletonList(profile), request, problems);
+ }
+
+ @Override
+ public Model injectProfiles(
+ Model model, List profiles, ModelBuildingRequest request, ModelProblemCollector problems) {
+ Model result = CACHE.computeIfAbsent(model, k -> new ConcurrentHashMap<>())
+ .computeIfAbsent(profiles, l -> doInjectProfiles(model, profiles));
+ return result == KEY ? model : result;
+ }
+
+ private Model doInjectProfiles(Model model, List profiles) {
+ Model orgModel = model;
+ for (Profile profile : profiles) {
+ if (profile != null) {
+ Model.Builder builder = Model.newBuilder(model);
+ merger.mergeModelBase(builder, model, profile);
+
+ if (profile.getBuild() != null) {
+ Build build = model.getBuild() != null ? model.getBuild() : Build.newInstance();
+ Build.Builder bbuilder = Build.newBuilder(build);
+ merger.mergeBuildBase(bbuilder, build, profile.getBuild());
+ builder.build(bbuilder.build());
+ }
+
+ model = builder.build();
}
-
- model.update(builder.build());
}
+ return model == orgModel ? KEY : model;
}
/**
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
index 45959f2ed1..b2d0e9a801 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
@@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.stream.Collectors;
import org.apache.maven.model.Activation;
import org.apache.maven.model.Profile;
@@ -61,6 +62,17 @@ public DefaultProfileSelector addProfileActivator(ProfileActivator profileActiva
return this;
}
+ @Override
+ public List getActiveProfilesV4(
+ Collection profiles,
+ ProfileActivationContext context,
+ ModelProblemCollector problems) {
+ return getActiveProfiles(profiles.stream().map(Profile::new).collect(Collectors.toList()), context, problems)
+ .stream()
+ .map(Profile::getDelegate)
+ .collect(Collectors.toList());
+ }
+
@Override
public List getActiveProfiles(
Collection profiles, ProfileActivationContext context, ModelProblemCollector problems) {
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
index ed62c86221..e4ab40015b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
@@ -18,6 +18,8 @@
*/
package org.apache.maven.model.profile;
+import java.util.List;
+
import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.building.ModelBuildingRequest;
@@ -39,4 +41,45 @@ public interface ProfileInjector {
* @param problems The container used to collect problems that were encountered, must not be {@code null}.
*/
void injectProfile(Model model, Profile profile, ModelBuildingRequest request, ModelProblemCollector problems);
+
+ /**
+ * Merges values from the specified profile into the given model. Implementations are expected to keep the profile
+ * and model completely decoupled by injecting deep copies rather than the original objects from the profile.
+ *
+ * @param model The model into which to merge the values defined by the profile, must not be null
.
+ * @param profile The (read-only) profile whose values should be injected, may be null
.
+ * @param request The model building request that holds further settings, must not be {@code null}.
+ * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+ */
+ default org.apache.maven.api.model.Model injectProfile(
+ org.apache.maven.api.model.Model model,
+ org.apache.maven.api.model.Profile profile,
+ ModelBuildingRequest request,
+ ModelProblemCollector problems) {
+ Model m = new Model(model);
+ injectProfile(m, profile != null ? new Profile(profile) : null, request, problems);
+ return m.getDelegate();
+ }
+
+ /**
+ * Merges values from the specified profile into the given model. Implementations are expected to keep the profile
+ * and model completely decoupled by injecting deep copies rather than the original objects from the profile.
+ *
+ * @param model The model into which to merge the values defined by the profile, must not be null
.
+ * @param profiles The (read-only) list of profiles whose values should be injected, must not be null
.
+ * @param request The model building request that holds further settings, must not be {@code null}.
+ * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+ */
+ default org.apache.maven.api.model.Model injectProfiles(
+ org.apache.maven.api.model.Model model,
+ List profiles,
+ ModelBuildingRequest request,
+ ModelProblemCollector problems) {
+ for (org.apache.maven.api.model.Profile profile : profiles) {
+ if (profile != null) {
+ model = injectProfile(model, profile, request, problems);
+ }
+ }
+ return model;
+ }
}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
index f0412961c6..a87d695e5c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
@@ -20,6 +20,7 @@
import java.util.Collection;
import java.util.List;
+import java.util.stream.Collectors;
import org.apache.maven.model.Profile;
import org.apache.maven.model.building.ModelProblemCollector;
@@ -42,4 +43,24 @@ public interface ProfileSelector {
*/
List getActiveProfiles(
Collection profiles, ProfileActivationContext context, ModelProblemCollector problems);
+
+ /**
+ * Determines the profiles which are active in the specified activation context. Active profiles will eventually be
+ * injected into the model.
+ *
+ * @param profiles The profiles whose activation status should be determined, must not be {@code null}.
+ * @param context The environmental context used to determine the activation status of a profile, must not be
+ * {@code null}.
+ * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+ * @return The profiles that have been activated, never {@code null}.
+ */
+ default List getActiveProfilesV4(
+ Collection profiles,
+ ProfileActivationContext context,
+ ModelProblemCollector problems) {
+ return getActiveProfiles(profiles.stream().map(Profile::new).collect(Collectors.toList()), context, problems)
+ .stream()
+ .map(Profile::getDelegate)
+ .collect(Collectors.toList());
+ }
}