diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
index d117d403fe00..d0bb81e37093 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 7af8f910a979..2c0fbbb19347 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
@@ -855,10 +855,7 @@ Model readParent(Model childModel) throws ModelBuilderException {
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(
@@ -883,43 +880,57 @@ Model readParent(Model childModel) throws ModelBuilderException {
return parentModel;
}
+ private Model resolveParent(Model childModel) {
+ Model parentModel = null;
+ if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_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, parentPath, parent);
+ 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();
- 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(""));
+ // Ensure that relative path and GA match, if both are provided
+ if (parentPath != null
+ && !parentPath.isEmpty()
+ && (groupId == null
+ || !groupId.equals(parent.getGroupId())
+ || artifactId == null
+ || !artifactId.equals(parent.getArtifactId()))) {
+ mismatchRelativePathAndGA(childModel, groupId, artifactId, parent);
return null;
}
- String version = getVersion(candidateModel);
if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
try {
VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion());
@@ -952,13 +963,35 @@ private Model readParentLocally(Model childModel) throws ModelBuilderException {
return null;
}
}
+ return candidateModel;
+ }
- //
- // Here we just need to know that a version is fine to use but this validation we can do in our workspace
- // resolver.
- //
+ private void mismatchRelativePathAndGA(Model childModel, String groupId, String artifactId, Parent parent) {
+ 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");
- return candidateModel;
+ setSource(childModel);
+ boolean warn = MODEL_VERSION_4_0_0.equals(childModel.getModelVersion());
+ add(warn ? Severity.WARNING : Severity.FATAL, Version.BASE, buffer.toString(), parent.getLocation(""));
+ }
+
+ private void wrongParentRelativePath(Model childModel, String parentPath, Parent parent) {
+ 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 {
@@ -987,13 +1020,10 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept
ModelSource modelSource;
try {
- modelSource = resolveReactorModel(groupId, artifactId, version);
- if (modelSource == null) {
- AtomicReference modified = new AtomicReference<>();
- modelSource = modelResolver.resolveModel(request.getSession(), repositories, parent, modified);
- if (modified.get() != null) {
- parent = modified.get();
- }
+ AtomicReference modified = new AtomicReference<>();
+ modelSource = modelResolver.resolveModel(request.getSession(), repositories, parent, modified);
+ if (modified.get() != null) {
+ parent = modified.get();
}
} catch (ModelResolverException e) {
// Message below is checked for in the MNG-2199 core IT.
@@ -1006,13 +1036,8 @@ Model resolveAndReadParentExternally(Model childModel) throws ModelBuilderExcept
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);
@@ -1831,15 +1856,6 @@ private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
|| 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 c8e875be4bb2..c0c0f4dc5824 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
@@ -325,6 +325,24 @@ public void validateFileModel(
"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) {