diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java index b9b68a7bb7d7..498e3e6dff49 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java @@ -53,14 +53,19 @@ public interface ModelBuildingRequest { int VALIDATION_LEVEL_MAVEN_3_0 = 30; /** - * Denotes validation as performed by Maven 3.1. This validation level is meant for new projects. + * Denotes validation as performed by Maven 3.1. This validation level is meant for existing projects. */ int VALIDATION_LEVEL_MAVEN_3_1 = 31; + /** + * Denotes validation as performed by Maven 4.0. This validation level is meant for new projects. + */ + int VALIDATION_LEVEL_MAVEN_4_0 = 40; + /** * Denotes strict validation as recommended by the current Maven version. */ - int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_3_1; + int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_4_0; /** * Gets the file model to build (with profile activation). diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java index 37e7b02363ac..d7b9adbb9c6e 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java @@ -23,6 +23,7 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -38,6 +39,7 @@ import org.codehaus.plexus.interpolation.AbstractValueSource; import org.codehaus.plexus.interpolation.InterpolationPostProcessor; import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.ObjectBasedValueSource; import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor; import org.codehaus.plexus.interpolation.PrefixedObjectValueSource; import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper; @@ -50,7 +52,10 @@ * @author jdcasey Created on Feb 3, 2005 */ public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator { - private static final List PROJECT_PREFIXES = Collections.singletonList("project."); + private static final String PREFIX_PROJECT = "project."; + private static final String PREFIX_POM = "pom."; + private static final List PROJECT_PREFIXES_3_1 = Arrays.asList(PREFIX_POM, PREFIX_PROJECT); + private static final List PROJECT_PREFIXES_4_0 = Collections.singletonList(PREFIX_PROJECT); private static final Collection TRANSLATED_PATH_EXPRESSIONS; @@ -95,14 +100,40 @@ public org.apache.maven.model.Model interpolateModel( return new org.apache.maven.model.Model(interpolateModel(model.getDelegate(), projectDir, request, problems)); } + protected List getProjectPrefixes(ModelBuildingRequest config) { + return config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0 + ? PROJECT_PREFIXES_4_0 + : PROJECT_PREFIXES_3_1; + } + protected List createValueSources( - final Model model, final File projectDir, final ModelBuildingRequest config) { + final Model model, + final File projectDir, + final ModelBuildingRequest config, + ModelProblemCollector problems) { Map modelProperties = model.getProperties(); - ValueSource projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false); + ValueSource projectPrefixValueSource; + ValueSource prefixlessObjectBasedValueSource; + if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0) { + projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_4_0, model, false); + prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model); + } else { + projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_3_1, model, false); + if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) { + projectPrefixValueSource = + new ProblemDetectingValueSource(projectPrefixValueSource, PREFIX_POM, PREFIX_PROJECT, problems); + } + + prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model); + if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) { + prefixlessObjectBasedValueSource = + new ProblemDetectingValueSource(prefixlessObjectBasedValueSource, "", PREFIX_PROJECT, problems); + } + } // NOTE: Order counts here! - List valueSources = new ArrayList<>(8); + List valueSources = new ArrayList<>(9); if (projectDir != null) { ValueSource basedirValueSource = new PrefixedValueSourceWrapper( @@ -115,7 +146,7 @@ public Object getValue(String expression) { return null; } }, - PROJECT_PREFIXES, + getProjectPrefixes(config), true); valueSources.add(basedirValueSource); @@ -133,7 +164,7 @@ public Object getValue(String expression) { return null; } }, - PROJECT_PREFIXES, + getProjectPrefixes(config), false); valueSources.add(baseUriValueSource); valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties)); @@ -151,7 +182,7 @@ public Object getValue(String expression) { return null; } }, - PROJECT_PREFIXES)); + getProjectPrefixes(config))); valueSources.add(projectPrefixValueSource); @@ -168,6 +199,8 @@ public Object getValue(String expression) { } }); + valueSources.add(prefixlessObjectBasedValueSource); + return valueSources; } @@ -176,14 +209,13 @@ protected List createPostProcessors( List processors = new ArrayList<>(2); if (projectDir != null) { processors.add(new PathTranslatingPostProcessor( - PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS, - projectDir, pathTranslator)); + getProjectPrefixes(config), TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator)); } processors.add(new UrlNormalizingPostProcessor(urlNormalizer)); return processors; } - protected RecursionInterceptor createRecursionInterceptor() { - return new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES); + protected RecursionInterceptor createRecursionInterceptor(ModelBuildingRequest config) { + return new PrefixAwareRecursionInterceptor(getProjectPrefixes(config)); } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java new file mode 100644 index 000000000000..53fabd27a03a --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java @@ -0,0 +1,76 @@ +/* + * 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.model.interpolation; + +import java.util.List; + +import org.apache.maven.model.building.ModelProblem.Severity; +import org.apache.maven.model.building.ModelProblem.Version; +import org.apache.maven.model.building.ModelProblemCollector; +import org.apache.maven.model.building.ModelProblemCollectorRequest; +import org.codehaus.plexus.interpolation.ValueSource; + +/** + * Wraps another value source and intercepts interpolated expressions, checking for problems. + * + * @author Benjamin Bentmann + */ +class ProblemDetectingValueSource implements ValueSource { + + private final ValueSource valueSource; + + private final String bannedPrefix; + + private final String newPrefix; + + private final ModelProblemCollector problems; + + ProblemDetectingValueSource( + ValueSource valueSource, String bannedPrefix, String newPrefix, ModelProblemCollector problems) { + this.valueSource = valueSource; + this.bannedPrefix = bannedPrefix; + this.newPrefix = newPrefix; + this.problems = problems; + } + + @Override + public Object getValue(String expression) { + Object value = valueSource.getValue(expression); + + if (value != null && expression.startsWith(bannedPrefix)) { + String msg = "The expression ${" + expression + "} is deprecated."; + if (newPrefix != null && newPrefix.length() > 0) { + msg += " Please use ${" + newPrefix + expression.substring(bannedPrefix.length()) + "} instead."; + } + problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20).setMessage(msg)); + } + + return value; + } + + @Override + public List getFeedback() { + return valueSource.getFeedback(); + } + + @Override + public void clearFeedback() { + valueSource.clearFeedback(); + } +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java index f2a511c03f5a..ae1d61773f46 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java @@ -64,10 +64,10 @@ interface InnerInterpolator { @Override public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems) { - List valueSources = createValueSources(model, projectDir, config); + List valueSources = createValueSources(model, projectDir, config, problems); List postProcessors = createPostProcessors(model, projectDir, config); - InnerInterpolator innerInterpolator = createInterpolator(valueSources, postProcessors, problems); + InnerInterpolator innerInterpolator = createInterpolator(valueSources, postProcessors, problems, config); return new MavenTransformer(innerInterpolator::interpolate).visit(model); } @@ -75,7 +75,8 @@ public Model interpolateModel( private InnerInterpolator createInterpolator( List valueSources, List postProcessors, - final ModelProblemCollector problems) { + final ModelProblemCollector problems, + ModelBuildingRequest config) { final Map cache = new HashMap<>(); final StringSearchInterpolator interpolator = new StringSearchInterpolator(); interpolator.setCacheAnswers(true); @@ -85,7 +86,7 @@ private InnerInterpolator createInterpolator( for (InterpolationPostProcessor postProcessor : postProcessors) { interpolator.addPostProcessor(postProcessor); } - final RecursionInterceptor recursionInterceptor = createRecursionInterceptor(); + final RecursionInterceptor recursionInterceptor = createRecursionInterceptor(config); return value -> { if (value != null && value.contains("${")) { String c = cache.get(value); diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java index 44a2a59ef575..f5a05242dae7 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java @@ -487,19 +487,47 @@ public void testRecursiveExpressionCycleBaseDir() throws Exception { @Test public void shouldIgnorePropertiesWithPomPrefix() throws Exception { final String orgName = "MyCo"; - final String expectedName = "${pom.organization.name} Tools"; + final String uninterpolatedName = "${pom.organization.name} Tools"; + final String interpolatedName = uninterpolatedName; Model model = Model.newBuilder() - .name(expectedName) + .name(uninterpolatedName) .organization(Organization.newBuilder().name(orgName).build()) .build(); ModelInterpolator interpolator = createInterpolator(); SimpleProblemCollector collector = new SimpleProblemCollector(); - Model out = interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector); + Model out = interpolator.interpolateModel( + model, + null, + createModelBuildingRequest(context).setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0), + collector); assertCollectorState(0, 0, 0, collector); - assertEquals(out.getName(), expectedName); + assertEquals(interpolatedName, out.getName()); + } + + @Test + public void shouldWarnPropertiesWithPomPrefix() throws Exception { + final String orgName = "MyCo"; + final String uninterpolatedName = "${pom.organization.name} Tools"; + final String interpolatedName = "MyCo Tools"; + + Model model = Model.newBuilder() + .name(uninterpolatedName) + .organization(Organization.newBuilder().name(orgName).build()) + .build(); + + ModelInterpolator interpolator = createInterpolator(); + SimpleProblemCollector collector = new SimpleProblemCollector(); + Model out = interpolator.interpolateModel( + model, + null, + createModelBuildingRequest(context).setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1), + collector); + + assertCollectorState(0, 0, 1, collector); + assertEquals(interpolatedName, out.getName()); } protected abstract ModelInterpolator createInterpolator() throws Exception;