diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index 3043a76a0ea6..04a6a9e62295 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -97,6 +97,30 @@
@Named
@Singleton
public class DefaultModelBuilder implements ModelBuilder {
+ /**
+ * Key for "fail on invalid model" property.
+ *
+ * Visible for testing.
+ */
+ static final String FAIL_ON_INVALID_MODEL = "maven.modelBuilder.failOnInvalidModel";
+
+ /**
+ * Checks user and system properties (in this order) for value of {@link #FAIL_ON_INVALID_MODEL} property key, if
+ * set and returns it. If not set, defaults to {@code true}.
+ *
+ * This is only meant to provide "escape hatch" for those builds, that are for some reason stuck with invalid models.
+ */
+ private static boolean isFailOnInvalidModel(ModelBuildingRequest request) {
+ String val = request.getUserProperties().getProperty(FAIL_ON_INVALID_MODEL);
+ if (val == null) {
+ val = request.getSystemProperties().getProperty(FAIL_ON_INVALID_MODEL);
+ }
+ if (val != null) {
+ return Boolean.parseBoolean(val);
+ }
+ return true;
+ }
+
@Inject
private ModelProcessor modelProcessor;
@@ -253,6 +277,7 @@ public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuild
protected ModelBuildingResult build(ModelBuildingRequest request, Collection importIds)
throws ModelBuildingException {
// phase 1
+ boolean failOnInvalidModel = isFailOnInvalidModel(request);
DefaultModelBuildingResult result = new DefaultModelBuildingResult();
DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
@@ -306,7 +331,7 @@ protected ModelBuildingResult build(ModelBuildingRequest request, Collection interpolatedActivations =
- getInterpolatedActivations(rawModel, profileActivationContext, problems);
+ getInterpolatedActivations(rawModel, profileActivationContext, failOnInvalidModel, problems);
injectProfileActivations(tmpModel, interpolatedActivations);
List activePomProfiles =
@@ -430,8 +455,12 @@ private interface InterpolateString {
}
private Map getInterpolatedActivations(
- Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
- Map interpolatedActivations = getProfileActivations(rawModel, true);
+ Model rawModel,
+ DefaultProfileActivationContext context,
+ boolean failOnInvalidModel,
+ DefaultModelProblemCollector problems) {
+ Map interpolatedActivations =
+ getProfileActivations(rawModel, true, failOnInvalidModel, problems);
if (interpolatedActivations.isEmpty()) {
return Collections.emptyMap();
@@ -753,7 +782,8 @@ private void assembleInheritance(
}
}
- private Map getProfileActivations(Model model, boolean clone) {
+ private Map getProfileActivations(
+ Model model, boolean clone, boolean failOnInvalidModel, ModelProblemCollector problems) {
Map activations = new HashMap<>();
for (Profile profile : model.getProfiles()) {
Activation activation = profile.getActivation();
@@ -766,7 +796,11 @@ private Map getProfileActivations(Model model, boolean clone
activation = activation.clone();
}
- activations.put(profile.getId(), activation);
+ if (activations.put(profile.getId(), activation) != null) {
+ problems.add(new ModelProblemCollectorRequest(
+ failOnInvalidModel ? Severity.FATAL : Severity.WARNING, ModelProblem.Version.BASE)
+ .setMessage("Duplicate activation for profile " + profile.getId()));
+ }
}
return activations;
@@ -787,7 +821,8 @@ private void injectProfileActivations(Model model, Map activ
private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
// save profile activations before interpolation, since they are evaluated with limited scope
- Map originalActivations = getProfileActivations(model, true);
+ // at this stage we already failed if wanted to
+ Map originalActivations = getProfileActivations(model, true, false, problems);
Model interpolatedModel =
modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
index 59fb44750003..13a8ac0e476b 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.maven.model.building;
+import java.io.File;
+
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Repository;
@@ -27,6 +29,8 @@
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Guillaume Nodet
@@ -87,6 +91,38 @@ public void testCycleInImports() throws Exception {
builder.build(request);
}
+ @Test
+ public void testBadProfiles() {
+ ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
+ assertNotNull(builder);
+
+ DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
+ request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ request.setModelSource(new FileModelSource(new File("src/test/resources/poms/building/badprofiles.xml")));
+ request.setModelResolver(new BaseModelResolver());
+
+ try {
+ builder.build(request); // throw, making "pom not available"
+ fail();
+ } catch (ModelBuildingException e) {
+ assertTrue(e.getMessage().contains("Duplicate activation for profile badprofile"));
+ }
+ }
+
+ @Test
+ public void testBadProfilesCheckDisabled() throws Exception {
+ ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
+ assertNotNull(builder);
+
+ DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
+ request.getUserProperties().setProperty(DefaultModelBuilder.FAIL_ON_INVALID_MODEL, "false");
+ request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ request.setModelSource(new FileModelSource(new File("src/test/resources/poms/building/badprofiles.xml")));
+ request.setModelResolver(new BaseModelResolver());
+
+ builder.build(request); // does not throw, old behaviour (but result may be fully off)
+ }
+
static class CycleInImportsResolver extends BaseModelResolver {
@Override
public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException {
diff --git a/maven-model-builder/src/test/resources/poms/building/badprofiles.xml b/maven-model-builder/src/test/resources/poms/building/badprofiles.xml
new file mode 100644
index 000000000000..e098a70fb946
--- /dev/null
+++ b/maven-model-builder/src/test/resources/poms/building/badprofiles.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+ 4.0.0
+
+ test
+ test
+ 0.1-SNAPSHOT
+ pom
+
+
+
+ badprofile
+
+ true
+
+
+ UTF-8
+
+
+
+ badprofile
+
+
+ simple.xml
+
+
+
+ activated
+
+
+
+