diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
index ccd39248b1..b9b3ebed9e 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
@@ -52,6 +52,10 @@ public interface ModelBuilderRequest {
* The request is for building a model from a POM file in a project on the filesystem.
*/
BUILD_POM,
+ /**
+ * The request is for building the consumer POM.
+ */
+ CONSUMER_POM,
/**
* The request is for building a model from a parent POM file from a downloaded artifact.
*/
diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
index 7df64f342b..4e29c4ffaf 100644
--- a/api/maven-api-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -1744,20 +1744,16 @@
relativePath
4.0.0+
- The relative path of the parent {@code pom.xml} file within the checkout.
- If not specified, it defaults to {@code ../pom.xml}.
+ The relative path of the parent subproject POM file or directory within the checkout.
+ If not specified, it defaults to {@code ..}, i.e. the parent directory.
Maven looks for the parent POM first in this location on
- the filesystem, then the local repository, and lastly in the remote repo.
- {@code relativePath} allows you to select a different location,
- for example when your structure is flat, or deeper without an intermediate parent POM.
- However, the group ID, artifact ID and version are still required,
- and must match the file in the location given, or it will revert to the repository for the POM.
- This feature is only for enhancing the development in a local checkout of that project.
- Set the value to an empty string in case you want to disable the feature and always resolve
- the parent POM from the repositories.
+ the filesystem if explicitly provided, then in the reactor if groupId and artifactId are provided,
+ then in the default parent directory, then the local repository, and lastly in the remote repo.
+ However, if the both relative path and the group ID / artifact ID are provided,
+ they must match the file in the location given.
+ Specify either the {@code relativePath} or the {@code groupId}/{@code artifactId}, not both.
String
- ..
diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java
index 4de108f1ff..bb1a7e23b7 100644
--- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java
+++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java
@@ -34,7 +34,6 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -829,6 +828,14 @@ public class DefaultModelBuilder implements ModelBuilder {
}
result.setEffectiveModel(resultModel);
+ // Set the default relative path for the parent in the file model
+ if (result.getFileModel().getParent() != null
+ && result.getFileModel().getParent().getRelativePath() == null) {
+ result.setFileModel(result.getFileModel()
+ .withParent(result.getFileModel()
+ .getParent()
+ .withRelativePath(resultModel.getParent().getRelativePath())));
+ }
// effective model validation
modelValidator.validateEffectiveModel(
@@ -849,10 +856,7 @@ public class DefaultModelBuilder implements ModelBuilder {
Parent parent = childModel.getParent();
if (parent != null) {
- parentModel = readParentLocally(childModel);
- if (parentModel == null) {
- parentModel = resolveAndReadParentExternally(childModel);
- }
+ parentModel = resolveParent(childModel);
if (!"pom".equals(parentModel.getPackaging())) {
add(
@@ -877,43 +881,56 @@ public class DefaultModelBuilder implements ModelBuilder {
return parentModel;
}
+ private Model resolveParent(Model childModel) {
+ Model parentModel = null;
+ if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM
+ || request.getRequestType() == ModelBuilderRequest.RequestType.CONSUMER_POM) {
+ parentModel = readParentLocally(childModel);
+ }
+ if (parentModel == null) {
+ parentModel = resolveAndReadParentExternally(childModel);
+ }
+ return parentModel;
+ }
+
private Model readParentLocally(Model childModel) throws ModelBuilderException {
- ModelSource candidateSource = getParentPomFile(childModel, request.getSource());
+ ModelSource candidateSource = null;
+
+ Parent parent = childModel.getParent();
+ String parentPath = parent.getRelativePath();
+ if (parentPath != null && !parentPath.isEmpty()) {
+ candidateSource = request.getSource().resolve(modelProcessor::locateExistingPom, parentPath);
+ if (candidateSource == null) {
+ wrongParentRelativePath(childModel);
+ return null;
+ }
+ }
+ if (candidateSource == null) {
+ candidateSource = resolveReactorModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
+ }
+ if (candidateSource == null) {
+ candidateSource = request.getSource().resolve(modelProcessor::locateExistingPom, "..");
+ }
+
if (candidateSource == null) {
return null;
}
Model candidateModel = derive(candidateSource).readAsParentModel();
- //
- // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we
- // have a model that is suitable, yet more checks are done here and the one for the version is problematic
- // before because with parents as ranges it will never work in this scenario.
- //
-
String groupId = getGroupId(candidateModel);
String artifactId = candidateModel.getArtifactId();
+ String version = getVersion(candidateModel);
- Parent parent = childModel.getParent();
+ // Ensure that relative path and GA match, if both are provided
if (groupId == null
|| !groupId.equals(parent.getGroupId())
|| artifactId == null
|| !artifactId.equals(parent.getArtifactId())) {
- StringBuilder buffer = new StringBuilder(256);
- buffer.append("'parent.relativePath'");
- if (childModel != getRootModel()) {
- buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
- }
- buffer.append(" points at ").append(groupId).append(':').append(artifactId);
- buffer.append(" instead of ").append(parent.getGroupId()).append(':');
- buffer.append(parent.getArtifactId()).append(", please verify your project structure");
-
- setSource(childModel);
- add(Severity.WARNING, Version.BASE, buffer.toString(), parent.getLocation(""));
+ mismatchRelativePathAndGA(childModel, groupId, artifactId);
return null;
}
- String version = getVersion(candidateModel);
if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
try {
VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion());
@@ -946,15 +963,41 @@ public class DefaultModelBuilder implements ModelBuilder {
return null;
}
}
-
- //
- // Here we just need to know that a version is fine to use but this validation we can do in our workspace
- // resolver.
- //
-
return candidateModel;
}
+ private void mismatchRelativePathAndGA(Model childModel, String groupId, String artifactId) {
+ Parent parent = childModel.getParent();
+ StringBuilder buffer = new StringBuilder(256);
+ buffer.append("'parent.relativePath'");
+ if (childModel != getRootModel()) {
+ buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
+ }
+ buffer.append(" points at ").append(groupId).append(':').append(artifactId);
+ buffer.append(" instead of ").append(parent.getGroupId()).append(':');
+ buffer.append(parent.getArtifactId()).append(", please verify your project structure");
+
+ setSource(childModel);
+ boolean warn = MODEL_VERSION_4_0_0.equals(childModel.getModelVersion())
+ || childModel.getParent().getRelativePath() == null;
+ add(warn ? Severity.WARNING : Severity.FATAL, Version.BASE, buffer.toString(), parent.getLocation(""));
+ }
+
+ private void wrongParentRelativePath(Model childModel) {
+ Parent parent = childModel.getParent();
+ String parentPath = parent.getRelativePath();
+ StringBuilder buffer = new StringBuilder(256);
+ buffer.append("'parent.relativePath'");
+ if (childModel != getRootModel()) {
+ buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
+ }
+ buffer.append(" points at '").append(parentPath);
+ buffer.append("' but no POM could be found, please verify your project structure");
+
+ setSource(childModel);
+ add(Severity.FATAL, Version.BASE, buffer.toString(), parent.getLocation(""));
+ }
+
Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderException {
ModelBuilderRequest request = this.request;
setSource(childModel);
@@ -981,7 +1024,7 @@ public class DefaultModelBuilder implements ModelBuilder {
ModelSource modelSource;
try {
- modelSource = resolveReactorModel(groupId, artifactId, version);
+ modelSource = resolveReactorModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
if (modelSource == null) {
AtomicReference modified = new AtomicReference<>();
modelSource = modelResolver.resolveModel(request.getSession(), repositories, parent, modified);
@@ -1000,13 +1043,8 @@ public class DefaultModelBuilder implements ModelBuilder {
buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
}
buffer.append(": ").append(e.getMessage());
- if (childModel.getProjectDirectory() != null) {
- if (parent.getRelativePath() == null
- || parent.getRelativePath().isEmpty()) {
- buffer.append(" and 'parent.relativePath' points at no local POM");
- } else {
- buffer.append(" and 'parent.relativePath' points at wrong local POM");
- }
+ if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) {
+ buffer.append(" and parent could not be found in reactor");
}
add(Severity.FATAL, Version.BASE, buffer.toString(), parent.getLocation(""), e);
@@ -1050,8 +1088,7 @@ public class DefaultModelBuilder implements ModelBuilder {
DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
setSource("(external profiles)");
- List activeExternalProfiles =
- profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, this);
+ List activeExternalProfiles = getActiveProfiles(request.getProfiles(), profileActivationContext);
result.setActiveExternalProfiles(activeExternalProfiles);
@@ -1066,8 +1103,7 @@ public class DefaultModelBuilder implements ModelBuilder {
profileActivationContext.setProjectProperties(inputModel.getProperties());
setSource(inputModel);
- List activePomProfiles =
- profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, this);
+ List activePomProfiles = getActiveProfiles(inputModel.getProfiles(), profileActivationContext);
// model normalization
setSource(inputModel);
@@ -1109,12 +1145,29 @@ public class DefaultModelBuilder implements ModelBuilder {
}
Model parentModel = readParent(inputModel);
+ // Now that we have read the parent, we can set the relative
+ // path correctly if it was not set in the input model
+ if (inputModel.getParent() != null && inputModel.getParent().getRelativePath() == null) {
+ String relPath;
+ if (parentModel.getPomFile() != null
+ && (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM
+ || request.getRequestType() == ModelBuilderRequest.RequestType.CONSUMER_POM)) {
+ relPath = inputModel
+ .getPomFile()
+ .getParent()
+ .relativize(parentModel.getPomFile().getParent())
+ .toString();
+ } else {
+ relPath = "..";
+ }
+ inputModel = inputModel.withParent(inputModel.getParent().withRelativePath(relPath));
+ }
List parentInterpolatedProfiles =
interpolateActivations(parentModel.getProfiles(), profileActivationContext, this);
// profile injection
List parentActivePomProfiles =
- profileSelector.getActiveProfiles(parentInterpolatedProfiles, profileActivationContext, this);
+ getActiveProfiles(parentInterpolatedProfiles, profileActivationContext);
Model injectedParentModel = profileInjector
.injectProfiles(parentModel, parentActivePomProfiles, request, this)
.withProfiles(List.of());
@@ -1131,8 +1184,7 @@ public class DefaultModelBuilder implements ModelBuilder {
interpolateActivations(model.getProfiles(), profileActivationContext, this);
// profile injection
- List activePomProfiles =
- profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this);
+ List activePomProfiles = getActiveProfiles(interpolatedProfiles, profileActivationContext);
result.setActivePomProfiles(activePomProfiles);
model = profileInjector.injectProfiles(model, activePomProfiles, request, this);
model = profileInjector.injectProfiles(model, activeExternalProfiles, request, this);
@@ -1160,6 +1212,15 @@ public class DefaultModelBuilder implements ModelBuilder {
return resultModel;
}
+ private List getActiveProfiles(
+ Collection interpolatedProfiles, DefaultProfileActivationContext profileActivationContext) {
+ if (request.getRequestType() != ModelBuilderRequest.RequestType.CONSUMER_POM) {
+ return profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this);
+ } else {
+ return List.of();
+ }
+ }
+
Model readFileModel() throws ModelBuilderException {
Model model = cache(request.getSource(), FILE, this::doReadFileModel);
// set the file model in the result outside the cache
@@ -1248,7 +1309,8 @@ public class DefaultModelBuilder implements ModelBuilder {
}
}
- if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) {
+ if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM
+ || request.getRequestType() == ModelBuilderRequest.RequestType.CONSUMER_POM) {
model = model.withPomFile(modelSource.getPath());
Parent parent = model.getParent();
@@ -1256,10 +1318,11 @@ public class DefaultModelBuilder implements ModelBuilder {
String groupId = parent.getGroupId();
String artifactId = parent.getArtifactId();
String version = parent.getVersion();
- String path = Optional.ofNullable(parent.getRelativePath()).orElse("..");
- if (version == null && !path.isEmpty()) {
+ String path = parent.getRelativePath();
+ if ((groupId == null || artifactId == null || version == null)
+ && (path == null || !path.isEmpty())) {
Path pomFile = model.getPomFile();
- Path relativePath = Paths.get(path);
+ Path relativePath = Paths.get(path != null ? path : "..");
Path pomPath = pomFile.resolveSibling(relativePath).normalize();
if (Files.isDirectory(pomPath)) {
pomPath = modelProcessor.locateExistingPom(pomPath);
@@ -1267,18 +1330,23 @@ public class DefaultModelBuilder implements ModelBuilder {
if (pomPath != null && Files.isRegularFile(pomPath)) {
Model parentModel =
derive(ModelSource.fromPath(pomPath)).readFileModel();
- if (parentModel != null) {
- String parentGroupId = getGroupId(parentModel);
- String parentArtifactId = parentModel.getArtifactId();
- String parentVersion = getVersion(parentModel);
- if ((groupId == null || groupId.equals(parentGroupId))
- && (artifactId == null || artifactId.equals(parentArtifactId))) {
- model = model.withParent(parent.with()
- .groupId(parentGroupId)
- .artifactId(parentArtifactId)
- .version(parentVersion)
- .build());
- }
+ String parentGroupId = getGroupId(parentModel);
+ String parentArtifactId = parentModel.getArtifactId();
+ String parentVersion = getVersion(parentModel);
+ if ((groupId == null || groupId.equals(parentGroupId))
+ && (artifactId == null || artifactId.equals(parentArtifactId))
+ && (version == null || version.equals(parentVersion))) {
+ model = model.withParent(parent.with()
+ .groupId(parentGroupId)
+ .artifactId(parentArtifactId)
+ .version(parentVersion)
+ .build());
+ } else {
+ mismatchRelativePathAndGA(model, parentGroupId, parentArtifactId);
+ }
+ } else {
+ if (!MODEL_VERSION_4_0_0.equals(model.getModelVersion()) && path != null) {
+ wrongParentRelativePath(model);
}
}
}
@@ -1369,7 +1437,8 @@ public class DefaultModelBuilder implements ModelBuilder {
Model rawModel = readFileModel();
if (!MODEL_VERSION_4_0_0.equals(rawModel.getModelVersion())
- && request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM) {
+ && (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_POM
+ || request.getRequestType() == ModelBuilderRequest.RequestType.CONSUMER_POM)) {
rawModel = transformFileToRaw(rawModel);
}
@@ -1600,7 +1669,7 @@ public class DefaultModelBuilder implements ModelBuilder {
.source(importSource)
.repositories(repositories)
.build();
- DefaultModelBuilderSession modelBuilderSession = new DefaultModelBuilderSession(importRequest);
+ DefaultModelBuilderSession modelBuilderSession = derive(importRequest);
// build the effective model
modelBuilderSession.buildEffectiveModel(importIds);
importResult = modelBuilderSession.result;
@@ -1812,15 +1881,6 @@ public class DefaultModelBuilder implements ModelBuilder {
|| rawChildModelVersion.equals("${project.parent.version}");
}
- private ModelSource getParentPomFile(Model childModel, ModelSource source) {
- String parentPath = childModel.getParent().getRelativePath();
- if (parentPath == null || parentPath.isEmpty()) {
- return null;
- } else {
- return source.resolve(modelProcessor::locateExistingPom, parentPath);
- }
- }
-
private Model getSuperModel(String modelVersion) {
return superPomProvider.getSuperPom(modelVersion);
}
diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java
index 94eb22f1dc..8867a82573 100644
--- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java
+++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelValidator.java
@@ -326,6 +326,24 @@ public class DefaultModelValidator implements ModelValidator {
"is either LATEST or RELEASE (both of them are being deprecated)",
parent);
}
+
+ if (parent.getRelativePath() != null
+ && !parent.getRelativePath().isEmpty()
+ && (parent.getGroupId() != null && !parent.getGroupId().isEmpty()
+ || parent.getArtifactId() != null
+ && !parent.getArtifactId().isEmpty())
+ && validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_4_0
+ && VALID_MODEL_VERSIONS.contains(m.getModelVersion())
+ && !Objects.equals(m.getModelVersion(), ModelBuilder.MODEL_VERSION_4_0_0)) {
+ addViolation(
+ problems,
+ Severity.WARNING,
+ Version.BASE,
+ "parent.relativePath",
+ null,
+ "only specify relativePath or groupId/artifactId in modelVersion 4.1.0",
+ parent);
+ }
}
if (validationLevel == ModelValidator.VALIDATION_LEVEL_MINIMAL) {
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
index d2953b2916..265dabdcd7 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
@@ -21,10 +21,14 @@ package org.apache.maven.internal.transformation.impl;
import javax.inject.Inject;
import javax.inject.Named;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.maven.api.SessionData;
@@ -35,42 +39,17 @@ import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.ModelBase;
import org.apache.maven.api.model.Profile;
import org.apache.maven.api.model.Repository;
-import org.apache.maven.api.services.Interpolator;
import org.apache.maven.api.services.ModelBuilder;
import org.apache.maven.api.services.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelBuilderResult;
-import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.ModelSource;
-import org.apache.maven.api.services.SuperPomProvider;
-import org.apache.maven.api.services.model.DependencyManagementImporter;
-import org.apache.maven.api.services.model.DependencyManagementInjector;
-import org.apache.maven.api.services.model.InheritanceAssembler;
+import org.apache.maven.api.services.Source;
import org.apache.maven.api.services.model.LifecycleBindingsInjector;
-import org.apache.maven.api.services.model.ModelCacheFactory;
-import org.apache.maven.api.services.model.ModelInterpolator;
-import org.apache.maven.api.services.model.ModelNormalizer;
-import org.apache.maven.api.services.model.ModelPathTranslator;
-import org.apache.maven.api.services.model.ModelProcessor;
-import org.apache.maven.api.services.model.ModelResolver;
-import org.apache.maven.api.services.model.ModelUrlNormalizer;
-import org.apache.maven.api.services.model.ModelValidator;
-import org.apache.maven.api.services.model.ModelVersionParser;
-import org.apache.maven.api.services.model.PluginConfigurationExpander;
-import org.apache.maven.api.services.model.PluginManagementInjector;
-import org.apache.maven.api.services.model.ProfileActivationContext;
-import org.apache.maven.api.services.model.ProfileInjector;
-import org.apache.maven.api.services.model.ProfileSelector;
-import org.apache.maven.api.spi.ModelTransformer;
import org.apache.maven.internal.impl.InternalSession;
-import org.apache.maven.internal.impl.model.DefaultModelBuilder;
-import org.apache.maven.internal.impl.model.DefaultProfileSelector;
-import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
import org.apache.maven.model.v4.MavenModelVersion;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystemSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Named
class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
@@ -78,74 +57,14 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
public static final String POM_PACKAGING = "pom";
- private final ProfileInjector profileInjector;
- private final InheritanceAssembler inheritanceAssembler;
- private final DependencyManagementImporter dependencyManagementImporter;
- private final DependencyManagementInjector dependencyManagementInjector;
private final LifecycleBindingsInjector lifecycleBindingsInjector;
- private final ModelInterpolator modelInterpolator;
- private final ModelNormalizer modelNormalizer;
- private final ModelPathTranslator modelPathTranslator;
- private final ModelProcessor modelProcessor;
- private final ModelUrlNormalizer modelUrlNormalizer;
- private final ModelValidator modelValidator;
- private final PluginConfigurationExpander pluginConfigurationExpander;
- private final PluginManagementInjector pluginManagementInjector;
- private final SuperPomProvider superPomProvider;
- private final ModelVersionParser versionParser;
- private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
- private final List transformers;
- private final ModelCacheFactory modelCacheFactory;
- private final ModelResolver modelResolver;
- private final Interpolator interpolator;
@Inject
@SuppressWarnings("checkstyle:ParameterNumber")
- DefaultConsumerPomBuilder(
- ProfileInjector profileInjector,
- InheritanceAssembler inheritanceAssembler,
- DependencyManagementImporter dependencyManagementImporter,
- DependencyManagementInjector dependencyManagementInjector,
- LifecycleBindingsInjector lifecycleBindingsInjector,
- ModelInterpolator modelInterpolator,
- ModelNormalizer modelNormalizer,
- ModelPathTranslator modelPathTranslator,
- ModelProcessor modelProcessor,
- ModelUrlNormalizer modelUrlNormalizer,
- ModelValidator modelValidator,
- PluginConfigurationExpander pluginConfigurationExpander,
- PluginManagementInjector pluginManagementInjector,
- SuperPomProvider superPomProvider,
- ModelVersionParser versionParser,
- ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
- List transformers,
- ModelCacheFactory modelCacheFactory,
- ModelResolver modelResolver,
- Interpolator interpolator) {
- this.profileInjector = profileInjector;
- this.inheritanceAssembler = inheritanceAssembler;
- this.dependencyManagementImporter = dependencyManagementImporter;
- this.dependencyManagementInjector = dependencyManagementInjector;
+ DefaultConsumerPomBuilder(LifecycleBindingsInjector lifecycleBindingsInjector) {
this.lifecycleBindingsInjector = lifecycleBindingsInjector;
- this.modelInterpolator = modelInterpolator;
- this.modelNormalizer = modelNormalizer;
- this.modelPathTranslator = modelPathTranslator;
- this.modelProcessor = modelProcessor;
- this.modelUrlNormalizer = modelUrlNormalizer;
- this.modelValidator = modelValidator;
- this.pluginConfigurationExpander = pluginConfigurationExpander;
- this.pluginManagementInjector = pluginManagementInjector;
- this.superPomProvider = superPomProvider;
- this.versionParser = versionParser;
- this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
- this.transformers = transformers;
- this.modelCacheFactory = modelCacheFactory;
- this.modelResolver = modelResolver;
- this.interpolator = interpolator;
}
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
@Override
public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuilderException {
Model model = project.getModel().getDelegate();
@@ -174,49 +93,18 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
private ModelBuilderResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
throws ModelBuilderException {
- ProfileSelector customSelector = new DefaultProfileSelector() {
- @Override
- public List getActiveProfiles(
- Collection profiles, ProfileActivationContext context, ModelProblemCollector problems) {
- return new ArrayList<>();
- }
- };
- // TODO: the custom selector should be used as a flag on the request
- DefaultModelBuilder modelBuilder = new DefaultModelBuilder(
- modelProcessor,
- modelValidator,
- modelNormalizer,
- modelInterpolator,
- modelPathTranslator,
- modelUrlNormalizer,
- superPomProvider,
- inheritanceAssembler,
- customSelector,
- profileInjector,
- pluginManagementInjector,
- dependencyManagementInjector,
- dependencyManagementImporter,
- pluginConfigurationExpander,
- profileActivationFilePathInterpolator,
- versionParser,
- transformers,
- modelCacheFactory,
- modelResolver,
- interpolator);
InternalSession iSession = InternalSession.from(session);
ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
- request.requestType(ModelBuilderRequest.RequestType.BUILD_POM);
+ request.requestType(ModelBuilderRequest.RequestType.CONSUMER_POM);
request.session(iSession);
- request.source(ModelSource.fromPath(src));
+ // in order to resolve parents, we need to fake being at the correct location
+ request.source(new PomConsumerModelSource(project.getModel().getPomPath(), src));
request.locationTracking(false);
request.systemProperties(session.getSystemProperties());
request.userProperties(session.getUserProperties());
request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings);
ModelBuilder.ModelBuilderSession mbSession =
iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class));
- if (mbSession == null) {
- mbSession = modelBuilder.newSession();
- }
return mbSession.build(request.build());
}
@@ -320,4 +208,63 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
.filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
.collect(Collectors.toList());
}
+
+ static class PomConsumerModelSource implements ModelSource {
+ final Path path;
+ final Path src;
+
+ PomConsumerModelSource(Path path, Path src) {
+ this.path = path;
+ this.src = src;
+ }
+
+ @Override
+ public Path getPath() {
+ return path;
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return Files.newInputStream(src);
+ }
+
+ @Override
+ public String getLocation() {
+ return src.toString();
+ }
+
+ @Override
+ public Source resolve(String relative) {
+ return ModelSource.fromPath(path.resolve(relative));
+ }
+
+ @Override
+ public ModelSource resolve(ModelLocator locator, String relative) {
+ String norm = relative.replace('\\', File.separatorChar).replace('/', File.separatorChar);
+ Path path = getPath().getParent().resolve(norm);
+ Path relatedPom = locator.locateExistingPom(path);
+ if (relatedPom != null) {
+ return ModelSource.fromPath(relatedPom);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o
+ || o.getClass() == getClass()
+ && Objects.equals(path, ((PomConsumerModelSource) o).path)
+ && Objects.equals(src, ((PomConsumerModelSource) o).src);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(path, src);
+ }
+
+ @Override
+ public String toString() {
+ return "PomConsumerModelSource[" + "path=" + path + ']';
+ }
+ }
}
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index 236ffe0055..954d3faf6d 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -74,6 +74,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.resolver.ArtifactDescriptorUtils;
+import org.apache.maven.model.building.DefaultModelProblem;
import org.apache.maven.model.building.FileModelSource;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.ModelSource2;
@@ -499,6 +500,11 @@ public class DefaultProjectBuilder implements ProjectBuilder {
List results = new ArrayList<>();
List allModels = results(result).toList();
for (ModelBuilderResult r : allModels) {
+ List problems = new ArrayList<>(r.getProblems());
+ results(r)
+ .filter(c -> c != r)
+ .flatMap(c -> c.getProblems().stream())
+ .forEach(problems::remove);
if (r.getEffectiveModel() != null) {
File pom = r.getSource().getPath().toFile();
MavenProject project =
@@ -510,7 +516,7 @@ public class DefaultProjectBuilder implements ProjectBuilder {
project.setExecutionRoot(pom.equals(pomFile));
initProject(project, r);
project.setCollectedProjects(results(r)
- .filter(cr -> cr != r)
+ .filter(cr -> cr != r && cr.getEffectiveModel() != null)
.map(cr -> projectIndex.get(cr.getEffectiveModel().getId()))
.collect(Collectors.toList()));
@@ -518,10 +524,9 @@ public class DefaultProjectBuilder implements ProjectBuilder {
if (request.isResolveDependencies()) {
resolutionResult = resolveDependencies(project);
}
- results.add(
- new DefaultProjectBuildingResult(project, convert(result.getProblems()), resolutionResult));
+ results.add(new DefaultProjectBuildingResult(project, convert(problems), resolutionResult));
} else {
- results.add(new DefaultProjectBuildingResult(null, convert(result.getProblems()), null));
+ results.add(new DefaultProjectBuildingResult(null, convert(problems), null));
}
}
return results;
@@ -535,20 +540,21 @@ public class DefaultProjectBuilder implements ProjectBuilder {
if (problems == null) {
return null;
}
- return problems.stream()
- .map(p -> (org.apache.maven.model.building.ModelProblem)
- new org.apache.maven.model.building.DefaultModelProblem(
- p.getMessage(),
- org.apache.maven.model.building.ModelProblem.Severity.valueOf(
- p.getSeverity().name()),
- org.apache.maven.model.building.ModelProblem.Version.valueOf(
- p.getVersion().name()),
- p.getSource(),
- p.getLineNumber(),
- p.getColumnNumber(),
- p.getModelId(),
- p.getException()))
- .toList();
+ return problems.stream().map(p -> convert(p)).toList();
+ }
+
+ private static org.apache.maven.model.building.ModelProblem convert(ModelProblem p) {
+ return new DefaultModelProblem(
+ p.getMessage(),
+ org.apache.maven.model.building.ModelProblem.Severity.valueOf(
+ p.getSeverity().name()),
+ org.apache.maven.model.building.ModelProblem.Version.valueOf(
+ p.getVersion().name()),
+ p.getSource(),
+ p.getLineNumber(),
+ p.getColumnNumber(),
+ p.getModelId(),
+ p.getException());
}
@SuppressWarnings({"checkstyle:methodlength", "deprecation"})
diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
index 0cf6c5c92c..2b58df1dc9 100644
--- a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
@@ -20,9 +20,6 @@ package org.apache.maven.internal.transformation.impl;
import javax.inject.Inject;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -35,17 +32,17 @@ import org.apache.maven.api.SessionData;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Parent;
import org.apache.maven.api.services.ModelBuilder;
+import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelSource;
import org.apache.maven.api.services.model.ModelResolver;
import org.apache.maven.api.services.model.ModelResolverException;
import org.apache.maven.api.spi.ModelTransformer;
import org.apache.maven.api.spi.ModelTransformerException;
import org.apache.maven.di.Injector;
+import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.internal.impl.InternalSession;
-import org.apache.maven.internal.impl.model.DefaultModelBuilder;
import org.apache.maven.internal.transformation.AbstractRepositoryTestCase;
-import org.apache.maven.model.v4.MavenStaxReader;
import org.apache.maven.project.MavenProject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -58,6 +55,9 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
@Inject
ConsumerPomBuilder builder;
+ @Inject
+ ModelBuilder modelBuilder;
+
@BeforeEach
void setupTransformerContext() throws Exception {
// We need to hack things a bit here to get the transformer context to work
@@ -71,33 +71,30 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
// to maven central
getContainer().lookup(Injector.class).bindImplicit(MyModelResolver.class);
InternalSession iSession = InternalSession.from(session);
- // set up the transformers
- List transformers = List.of(new CIFriendlyVersionModelTransformer(iSession));
- Field transformersField = DefaultModelBuilder.class.getDeclaredField("transformers");
- transformersField.setAccessible(true);
- DefaultModelBuilder modelBuilder = (DefaultModelBuilder) getContainer().lookup(ModelBuilder.class);
- transformersField.set(modelBuilder, transformers);
- transformersField = DefaultConsumerPomBuilder.class.getDeclaredField("transformers");
- transformersField.setAccessible(true);
- transformersField.set(builder, transformers);
// set up the model resolver
iSession.getData().set(SessionData.key(ModelResolver.class), new MyModelResolver());
}
@Test
void testTrivialConsumer() throws Exception {
- MavenProject project;
- Path file = Paths.get("src/test/resources/consumer/trivial/child/pom.xml");
- try (InputStream inputStream = Files.newInputStream(file)) {
- org.apache.maven.model.Model model =
- new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
- project = new MavenProject(model);
- project.setOriginalModel(model);
- }
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");
+
+ 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(ModelSource.fromPath(file))
+ .requestType(ModelBuilderRequest.RequestType.BUILD_POM)
+ .build())
+ .getEffectiveModel();
+
+ MavenProject project = new MavenProject(orgModel);
+ project.setOriginalModel(new org.apache.maven.model.Model(orgModel));
Model model = builder.build(session, project, file);
assertNotNull(model);
@@ -105,24 +102,26 @@ public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
@Test
void testSimpleConsumer() throws Exception {
- MavenProject project;
+ MavenExecutionRequest request = InternalMavenSession.from(InternalSession.from(session))
+ .getMavenSession()
+ .getRequest();
+ request.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
+ request.getUserProperties().setProperty("changelist", "MNG6957");
+
Path file = Paths.get("src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml");
- InternalMavenSession.from(InternalSession.from(session))
- .getMavenSession()
- .getRequest()
- .getUserProperties()
- .setProperty("changelist", "MNG6957");
- try (InputStream inputStream = Files.newInputStream(file)) {
- org.apache.maven.model.Model model =
- new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
- project = new MavenProject(model);
- project.setOriginalModel(model);
- }
- InternalMavenSession.from(InternalSession.from(session))
- .getMavenSession()
- .getRequest()
- .setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
+ 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(ModelSource.fromPath(file))
+ .requestType(ModelBuilderRequest.RequestType.BUILD_POM)
+ .build())
+ .getEffectiveModel();
+
+ MavenProject project = new MavenProject(orgModel);
+ project.setOriginalModel(new org.apache.maven.model.Model(orgModel));
+ request.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
Model model = builder.build(session, project, file);
assertNotNull(model);
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 990c2cfb80..8dd4de675c 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
@@ -1616,8 +1616,10 @@ public class DefaultModelBuilder implements ModelBuilder {
}
String parentPath = childModel.getParent().getRelativePath();
-
- if (parentPath == null || parentPath.isEmpty()) {
+ if (parentPath == null) {
+ parentPath = "..";
+ childModel.getParent().setRelativePath(parentPath);
+ } else if (parentPath.isEmpty()) {
return null;
}