Skip to content

Commit cb5ee55

Browse files
authored
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.
1 parent 598857d commit cb5ee55

File tree

2 files changed

+242
-1
lines changed

2 files changed

+242
-1
lines changed

impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,13 @@ private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
581581
results.add(new DefaultProjectBuildingResult(
582582
project, convert(r.getProblemCollector()), resolutionResult));
583583
} else {
584-
results.add(new DefaultProjectBuildingResult(null, convert(r.getProblemCollector()), null));
584+
// Extract project identification even when effective model is null
585+
String projectId = extractProjectId(r);
586+
File sourcePomFile = r.getSource() != null && r.getSource().getPath() != null
587+
? r.getSource().getPath().toFile()
588+
: null;
589+
results.add(new DefaultProjectBuildingResult(
590+
projectId, sourcePomFile, convert(r.getProblemCollector())));
585591
}
586592
}
587593
return results;
@@ -1013,6 +1019,27 @@ private static ModelSource createStubModelSource(Artifact artifact) {
10131019
return new StubModelSource(xml, artifact);
10141020
}
10151021

1022+
/**
1023+
* Extracts project identification from ModelBuilderResult, falling back to rawModel or fileModel
1024+
* when effectiveModel is null, similar to ModelBuilderException.getModelId().
1025+
*/
1026+
private static String extractProjectId(ModelBuilderResult result) {
1027+
Model model = null;
1028+
if (result.getEffectiveModel() != null) {
1029+
model = result.getEffectiveModel();
1030+
} else if (result.getRawModel() != null) {
1031+
model = result.getRawModel();
1032+
} else if (result.getFileModel() != null) {
1033+
model = result.getFileModel();
1034+
}
1035+
1036+
if (model != null) {
1037+
return model.getId();
1038+
}
1039+
1040+
return "";
1041+
}
1042+
10161043
static String getGroupId(Model model) {
10171044
String groupId = model.getGroupId();
10181045
if (groupId == null && model.getParent() != null) {
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.project;
20+
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.lang.reflect.Method;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.util.List;
27+
28+
import org.apache.maven.api.model.Model;
29+
import org.apache.maven.api.model.Profile;
30+
import org.apache.maven.api.services.ModelBuilderRequest;
31+
import org.apache.maven.api.services.ModelBuilderResult;
32+
import org.apache.maven.api.services.ModelProblem;
33+
import org.apache.maven.api.services.ModelSource;
34+
import org.apache.maven.api.services.ProblemCollector;
35+
import org.apache.maven.api.services.Source;
36+
import org.junit.jupiter.api.Test;
37+
38+
import static org.junit.jupiter.api.Assertions.assertEquals;
39+
import static org.junit.jupiter.api.Assertions.assertNotNull;
40+
41+
/**
42+
* Test for {@link DefaultProjectBuilder} extractProjectId method.
43+
*/
44+
@SuppressWarnings("deprecation")
45+
class DefaultProjectBuilderTest {
46+
47+
/**
48+
* Test the extractProjectId method to ensure it properly falls back to rawModel or fileModel
49+
* when effectiveModel is null, addressing issue #11292.
50+
*/
51+
@Test
52+
void testExtractProjectIdFallback() throws Exception {
53+
// Use reflection to access the private extractProjectId method
54+
Method extractProjectIdMethod =
55+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId", ModelBuilderResult.class);
56+
extractProjectIdMethod.setAccessible(true);
57+
58+
// Create a mock ModelBuilderResult with null effectiveModel but available rawModel
59+
ModelBuilderResult mockResult = new MockModelBuilderResult(
60+
null, // effectiveModel is null
61+
createMockModel("com.example", "test-project", "1.0.0"), // rawModel is available
62+
null // fileModel is null
63+
);
64+
65+
String projectId = (String) extractProjectIdMethod.invoke(null, mockResult);
66+
67+
assertNotNull(projectId, "Project ID should not be null");
68+
assertEquals(
69+
"com.example:test-project:jar:1.0.0",
70+
projectId,
71+
"Should extract project ID from rawModel when effectiveModel is null");
72+
}
73+
74+
/**
75+
* Test extractProjectId with fileModel fallback when both effectiveModel and rawModel are null.
76+
*/
77+
@Test
78+
void testExtractProjectIdFileModelFallback() throws Exception {
79+
Method extractProjectIdMethod =
80+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId", ModelBuilderResult.class);
81+
extractProjectIdMethod.setAccessible(true);
82+
83+
ModelBuilderResult mockResult = new MockModelBuilderResult(
84+
null, // effectiveModel is null
85+
null, // rawModel is null
86+
createMockModel("com.example", "test-project", "1.0.0") // fileModel is available
87+
);
88+
89+
String projectId = (String) extractProjectIdMethod.invoke(null, mockResult);
90+
91+
assertNotNull(projectId, "Project ID should not be null");
92+
assertEquals(
93+
"com.example:test-project:jar:1.0.0",
94+
projectId,
95+
"Should extract project ID from fileModel when effectiveModel and rawModel are null");
96+
}
97+
98+
/**
99+
* Test extractProjectId returns empty string when all models are null.
100+
*/
101+
@Test
102+
void testExtractProjectIdAllModelsNull() throws Exception {
103+
Method extractProjectIdMethod =
104+
DefaultProjectBuilder.class.getDeclaredMethod("extractProjectId", ModelBuilderResult.class);
105+
extractProjectIdMethod.setAccessible(true);
106+
107+
ModelBuilderResult mockResult = new MockModelBuilderResult(null, null, null);
108+
109+
String projectId = (String) extractProjectIdMethod.invoke(null, mockResult);
110+
111+
assertNotNull(projectId, "Project ID should not be null");
112+
assertEquals("", projectId, "Should return empty string when all models are null");
113+
}
114+
115+
private Model createMockModel(String groupId, String artifactId, String version) {
116+
return Model.newBuilder()
117+
.groupId(groupId)
118+
.artifactId(artifactId)
119+
.version(version)
120+
.packaging("jar")
121+
.build();
122+
}
123+
124+
/**
125+
* Mock implementation of ModelBuilderResult for testing.
126+
*/
127+
private static class MockModelBuilderResult implements ModelBuilderResult {
128+
private final Model effectiveModel;
129+
private final Model rawModel;
130+
private final Model fileModel;
131+
132+
MockModelBuilderResult(Model effectiveModel, Model rawModel, Model fileModel) {
133+
this.effectiveModel = effectiveModel;
134+
this.rawModel = rawModel;
135+
this.fileModel = fileModel;
136+
}
137+
138+
@Override
139+
public Model getEffectiveModel() {
140+
return effectiveModel;
141+
}
142+
143+
@Override
144+
public Model getRawModel() {
145+
return rawModel;
146+
}
147+
148+
@Override
149+
public Model getFileModel() {
150+
return fileModel;
151+
}
152+
153+
@Override
154+
public ModelBuilderRequest getRequest() {
155+
return null;
156+
}
157+
158+
// Other required methods with minimal implementations
159+
@Override
160+
public ModelSource getSource() {
161+
return new ModelSource() {
162+
@Override
163+
public Path getPath() {
164+
return Paths.get("test-pom.xml");
165+
}
166+
167+
@Override
168+
public String getLocation() {
169+
return "test-pom.xml";
170+
}
171+
172+
@Override
173+
public InputStream openStream() throws IOException {
174+
return null;
175+
}
176+
177+
@Override
178+
public Source resolve(String relative) {
179+
return null;
180+
}
181+
182+
@Override
183+
public ModelSource resolve(ModelSource.ModelLocator modelLocator, String relative) {
184+
return null;
185+
}
186+
};
187+
}
188+
189+
@Override
190+
public Model getParentModel() {
191+
return null;
192+
}
193+
194+
@Override
195+
public List<Profile> getActivePomProfiles() {
196+
return List.of();
197+
}
198+
199+
@Override
200+
public List<Profile> getActiveExternalProfiles() {
201+
return List.of();
202+
}
203+
204+
@Override
205+
public ProblemCollector<ModelProblem> getProblemCollector() {
206+
return null;
207+
}
208+
209+
@Override
210+
public List<? extends ModelBuilderResult> getChildren() {
211+
return List.of();
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)