This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new cb5ee55803 Fix [unknown project] messages in error output (#11324)
cb5ee55803 is described below
commit cb5ee55803a7f2acf49b86945d7df7101312b6aa
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Oct 28 18:09:27 2025 +0100
Fix [unknown project] messages in error output (#11324)
Resolves issue #11292 where Maven shows '[unknown project]' in error
messages when using -e -X flags, particularly in CI environments.
The issue occurred because DefaultProjectBuilder was creating
DefaultProjectBuildingResult with null project information when
ModelBuilderResult.getEffectiveModel() returned null, resulting in
empty projectId and causing ProjectBuildingException.createMessage()
to display '[unknown project]' as a fallback.
This fix extracts project identification from available model data
(rawModel or fileModel) when effectiveModel is null, following the
same pattern used in ModelBuilderException.getModelId().
Changes:
- Added extractProjectId() helper method that falls back to rawModel
or fileModel when effectiveModel is null
- Modified project building result creation to use extracted projectId
and POM file information instead of null values
- Maintains backward compatibility: when all models are null, still
returns empty string to preserve '[unknown project]' fallback for
truly unknown projects
This provides better error messages showing meaningful project
identification like 'com.example:my-project:jar:1.0.0' even when
project building fails, while maintaining existing error handling
patterns.
---
.../maven/project/DefaultProjectBuilder.java | 29 ++-
.../maven/project/DefaultProjectBuilderTest.java | 214 +++++++++++++++++++++
2 files changed, 242 insertions(+), 1 deletion(-)
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index 245d85117d..5b2576eb9d 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -581,7 +581,13 @@ private List<ProjectBuildingResult> build(File pomFile,
boolean recursive) {
results.add(new DefaultProjectBuildingResult(
project, convert(r.getProblemCollector()),
resolutionResult));
} else {
- results.add(new DefaultProjectBuildingResult(null,
convert(r.getProblemCollector()), null));
+ // Extract project identification even when effective
model is null
+ String projectId = extractProjectId(r);
+ File sourcePomFile = r.getSource() != null &&
r.getSource().getPath() != null
+ ? r.getSource().getPath().toFile()
+ : null;
+ results.add(new DefaultProjectBuildingResult(
+ projectId, sourcePomFile,
convert(r.getProblemCollector())));
}
}
return results;
@@ -1013,6 +1019,27 @@ private static ModelSource
createStubModelSource(Artifact artifact) {
return new StubModelSource(xml, artifact);
}
+ /**
+ * Extracts project identification from ModelBuilderResult, falling back
to rawModel or fileModel
+ * when effectiveModel is null, similar to
ModelBuilderException.getModelId().
+ */
+ private static String extractProjectId(ModelBuilderResult result) {
+ Model model = null;
+ if (result.getEffectiveModel() != null) {
+ model = result.getEffectiveModel();
+ } else if (result.getRawModel() != null) {
+ model = result.getRawModel();
+ } else if (result.getFileModel() != null) {
+ model = result.getFileModel();
+ }
+
+ if (model != null) {
+ return model.getId();
+ }
+
+ return "";
+ }
+
static String getGroupId(Model model) {
String groupId = model.getGroupId();
if (groupId == null && model.getParent() != null) {
diff --git
a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultProjectBuilderTest.java
b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultProjectBuilderTest.java
new file mode 100644
index 0000000000..7532aebbc1
--- /dev/null
+++
b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultProjectBuilderTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.project;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.services.ModelBuilderRequest;
+import org.apache.maven.api.services.ModelBuilderResult;
+import org.apache.maven.api.services.ModelProblem;
+import org.apache.maven.api.services.ModelSource;
+import org.apache.maven.api.services.ProblemCollector;
+import org.apache.maven.api.services.Source;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Test for {@link DefaultProjectBuilder} extractProjectId method.
+ */
+@SuppressWarnings("deprecation")
+class DefaultProjectBuilderTest {
+
+ /**
+ * Test the extractProjectId method to ensure it properly falls back to
rawModel or fileModel
+ * when effectiveModel is null, addressing issue #11292.
+ */
+ @Test
+ void testExtractProjectIdFallback() throws Exception {
+ // Use reflection to access the private extractProjectId method
+ Method extractProjectIdMethod =
+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId",
ModelBuilderResult.class);
+ extractProjectIdMethod.setAccessible(true);
+
+ // Create a mock ModelBuilderResult with null effectiveModel but
available rawModel
+ ModelBuilderResult mockResult = new MockModelBuilderResult(
+ null, // effectiveModel is null
+ createMockModel("com.example", "test-project", "1.0.0"), //
rawModel is available
+ null // fileModel is null
+ );
+
+ String projectId = (String) extractProjectIdMethod.invoke(null,
mockResult);
+
+ assertNotNull(projectId, "Project ID should not be null");
+ assertEquals(
+ "com.example:test-project:jar:1.0.0",
+ projectId,
+ "Should extract project ID from rawModel when effectiveModel
is null");
+ }
+
+ /**
+ * Test extractProjectId with fileModel fallback when both effectiveModel
and rawModel are null.
+ */
+ @Test
+ void testExtractProjectIdFileModelFallback() throws Exception {
+ Method extractProjectIdMethod =
+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId",
ModelBuilderResult.class);
+ extractProjectIdMethod.setAccessible(true);
+
+ ModelBuilderResult mockResult = new MockModelBuilderResult(
+ null, // effectiveModel is null
+ null, // rawModel is null
+ createMockModel("com.example", "test-project", "1.0.0") //
fileModel is available
+ );
+
+ String projectId = (String) extractProjectIdMethod.invoke(null,
mockResult);
+
+ assertNotNull(projectId, "Project ID should not be null");
+ assertEquals(
+ "com.example:test-project:jar:1.0.0",
+ projectId,
+ "Should extract project ID from fileModel when effectiveModel
and rawModel are null");
+ }
+
+ /**
+ * Test extractProjectId returns empty string when all models are null.
+ */
+ @Test
+ void testExtractProjectIdAllModelsNull() throws Exception {
+ Method extractProjectIdMethod =
+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId",
ModelBuilderResult.class);
+ extractProjectIdMethod.setAccessible(true);
+
+ ModelBuilderResult mockResult = new MockModelBuilderResult(null, null,
null);
+
+ String projectId = (String) extractProjectIdMethod.invoke(null,
mockResult);
+
+ assertNotNull(projectId, "Project ID should not be null");
+ assertEquals("", projectId, "Should return empty string when all
models are null");
+ }
+
+ private Model createMockModel(String groupId, String artifactId, String
version) {
+ return Model.newBuilder()
+ .groupId(groupId)
+ .artifactId(artifactId)
+ .version(version)
+ .packaging("jar")
+ .build();
+ }
+
+ /**
+ * Mock implementation of ModelBuilderResult for testing.
+ */
+ private static class MockModelBuilderResult implements ModelBuilderResult {
+ private final Model effectiveModel;
+ private final Model rawModel;
+ private final Model fileModel;
+
+ MockModelBuilderResult(Model effectiveModel, Model rawModel, Model
fileModel) {
+ this.effectiveModel = effectiveModel;
+ this.rawModel = rawModel;
+ this.fileModel = fileModel;
+ }
+
+ @Override
+ public Model getEffectiveModel() {
+ return effectiveModel;
+ }
+
+ @Override
+ public Model getRawModel() {
+ return rawModel;
+ }
+
+ @Override
+ public Model getFileModel() {
+ return fileModel;
+ }
+
+ @Override
+ public ModelBuilderRequest getRequest() {
+ return null;
+ }
+
+ // Other required methods with minimal implementations
+ @Override
+ public ModelSource getSource() {
+ return new ModelSource() {
+ @Override
+ public Path getPath() {
+ return Paths.get("test-pom.xml");
+ }
+
+ @Override
+ public String getLocation() {
+ return "test-pom.xml";
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public Source resolve(String relative) {
+ return null;
+ }
+
+ @Override
+ public ModelSource resolve(ModelSource.ModelLocator
modelLocator, String relative) {
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Model getParentModel() {
+ return null;
+ }
+
+ @Override
+ public List<Profile> getActivePomProfiles() {
+ return List.of();
+ }
+
+ @Override
+ public List<Profile> getActiveExternalProfiles() {
+ return List.of();
+ }
+
+ @Override
+ public ProblemCollector<ModelProblem> getProblemCollector() {
+ return null;
+ }
+
+ @Override
+ public List<? extends ModelBuilderResult> getChildren() {
+ return List.of();
+ }
+ }
+}