1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.exception;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.io.IOException;
25 import java.net.ConnectException;
26 import java.net.UnknownHostException;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.IdentityHashMap;
30 import java.util.List;
31 import java.util.Set;
32
33 import org.apache.maven.api.plugin.MojoException;
34 import org.apache.maven.lifecycle.LifecycleExecutionException;
35 import org.apache.maven.model.building.ModelProblem;
36 import org.apache.maven.model.building.ModelProblemUtils;
37 import org.apache.maven.plugin.AbstractMojoExecutionException;
38 import org.apache.maven.plugin.MojoExecutionException;
39 import org.apache.maven.plugin.PluginContainerException;
40 import org.apache.maven.plugin.PluginExecutionException;
41 import org.apache.maven.project.ProjectBuildingException;
42 import org.apache.maven.project.ProjectBuildingResult;
43 import org.eclipse.aether.transfer.ArtifactFilteredOutException;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 @Named
94 @Singleton
95 public class DefaultExceptionHandler implements ExceptionHandler {
96 @Override
97 public ExceptionSummary handleException(Throwable exception) {
98 return handle("", exception);
99 }
100
101 private ExceptionSummary handle(String message, Throwable exception) {
102 String reference = getReference(Collections.newSetFromMap(new IdentityHashMap<>()), exception);
103
104 List<ExceptionSummary> children = null;
105
106 if (exception instanceof ProjectBuildingException projectBuildingException) {
107 List<ProjectBuildingResult> results = projectBuildingException.getResults();
108
109 children = new ArrayList<>();
110
111 for (ProjectBuildingResult result : results) {
112 ExceptionSummary child = handle(result);
113 if (child != null) {
114 children.add(child);
115 }
116 }
117
118 message = "The build could not read " + children.size() + " project" + (children.size() == 1 ? "" : "s");
119 } else {
120 message = getMessage(message, exception);
121 }
122
123 return new ExceptionSummary(exception, message, reference, children);
124 }
125
126 private ExceptionSummary handle(ProjectBuildingResult result) {
127 List<ExceptionSummary> children = new ArrayList<>();
128
129 for (ModelProblem problem : result.getProblems()) {
130 ExceptionSummary child = handle(problem, result.getProjectId());
131 if (child != null) {
132 children.add(child);
133 }
134 }
135
136 if (children.isEmpty()) {
137 return null;
138 }
139
140 String message = System.lineSeparator()
141 + "The project " + (result.getProjectId().isEmpty() ? "" : result.getProjectId() + " ")
142 + "(" + result.getPomFile() + ") has "
143 + children.size() + " error" + (children.size() == 1 ? "" : "s");
144
145 return new ExceptionSummary(null, message, null, children);
146 }
147
148 private ExceptionSummary handle(ModelProblem problem, String projectId) {
149 if (ModelProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
150 String message = problem.getMessage();
151
152 String location = ModelProblemUtils.formatLocation(problem, projectId);
153
154 if (!location.isEmpty()) {
155 message += " @ " + location;
156 }
157
158 return handle(message, problem.getException());
159 } else {
160 return null;
161 }
162 }
163
164 private String getReference(Set<Throwable> dejaVu, Throwable exception) {
165 String reference = "";
166 if (!dejaVu.add(exception)) {
167 return reference;
168 }
169
170 if (exception != null) {
171 if (exception instanceof MojoExecutionException) {
172 reference = MojoExecutionException.class.getSimpleName();
173
174 Throwable cause = exception.getCause();
175 if (cause instanceof IOException) {
176 cause = cause.getCause();
177 if (cause instanceof ConnectException) {
178 reference = ConnectException.class.getSimpleName();
179 }
180 }
181 if (findCause(exception, ArtifactFilteredOutException.class) != null) {
182 reference = "https://maven.apache.org/resolver/remote-repository-filtering.html";
183 }
184 } else if (exception instanceof LinkageError) {
185 reference = LinkageError.class.getSimpleName();
186 } else if (exception instanceof PluginExecutionException) {
187 Throwable cause = exception.getCause();
188
189 if (cause instanceof PluginContainerException) {
190 Throwable cause2 = cause.getCause();
191
192 if (cause2 instanceof NoClassDefFoundError) {
193 String message = cause2.getMessage();
194 if (message != null && message.contains("org/sonatype/aether/")) {
195 reference = "AetherClassNotFound";
196 }
197 }
198 }
199
200 if (reference == null || reference.isEmpty()) {
201 reference = getReference(dejaVu, cause);
202 }
203
204 if (reference == null || reference.isEmpty()) {
205 reference = exception.getClass().getSimpleName();
206 }
207 } else if (exception instanceof LifecycleExecutionException) {
208 reference = getReference(dejaVu, exception.getCause());
209 } else if (isNoteworthyException(exception)) {
210 reference = exception.getClass().getSimpleName();
211 }
212 }
213
214 if ((reference != null && !reference.isEmpty())
215 && !reference.startsWith("http:")
216 && !reference.startsWith("https:")) {
217 reference = "http://cwiki.apache.org/confluence/display/MAVEN/" + reference;
218 }
219
220 return reference;
221 }
222
223 private boolean isNoteworthyException(Throwable exception) {
224 if (exception == null) {
225 return false;
226 } else if (exception instanceof Error) {
227 return true;
228 } else if (exception instanceof RuntimeException) {
229 return false;
230 } else {
231 return !exception.getClass().getName().startsWith("java");
232 }
233 }
234
235 private String getMessage(String message, Throwable exception) {
236 String fullMessage = (message != null) ? message : "";
237
238 boolean hasArtifactFilteredOut = false;
239
240
241 Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
242 for (Throwable t = exception; t != null && t != t.getCause(); t = t.getCause()) {
243 String exceptionMessage = t.getMessage();
244 String longMessage = null;
245
246 if (t instanceof AbstractMojoExecutionException abstractMojoExecutionException) {
247 longMessage = abstractMojoExecutionException.getLongMessage();
248 } else if (t instanceof MojoException mojoException) {
249 longMessage = mojoException.getLongMessage();
250 }
251
252 if (longMessage != null && !longMessage.isEmpty()) {
253 if ((exceptionMessage == null || exceptionMessage.isEmpty())
254 || longMessage.contains(exceptionMessage)) {
255 exceptionMessage = longMessage;
256 } else if (!exceptionMessage.contains(longMessage)) {
257 exceptionMessage = join(exceptionMessage, System.lineSeparator() + longMessage);
258 }
259 }
260
261 if (exceptionMessage == null || exceptionMessage.isEmpty()) {
262 exceptionMessage = t.getClass().getSimpleName();
263 }
264
265 if (t instanceof UnknownHostException && !fullMessage.contains("host")) {
266 fullMessage = join(fullMessage, "Unknown host " + exceptionMessage);
267 } else if (!fullMessage.contains(exceptionMessage)) {
268 fullMessage = join(fullMessage, exceptionMessage);
269 }
270
271 if (t instanceof ArtifactFilteredOutException) {
272 hasArtifactFilteredOut = true;
273 }
274
275 if (!dejaVu.add(t)) {
276 fullMessage = join(fullMessage, "[CIRCULAR REFERENCE]");
277 break;
278 }
279 }
280
281 if (hasArtifactFilteredOut) {
282 fullMessage += """
283
284 This error indicates that a remote repository filter has rejected this artifact. This commonly happens with repository managers using virtual/group repositories that do not properly aggregate prefix files.
285 To disable remote repository filtering, add one or both of these to your command line or to .mvn/maven.config:
286 -Daether.remoteRepositoryFilter.prefixes=false
287 -Daether.remoteRepositoryFilter.groupId=false
288 See https:
289 }
290
291 return fullMessage.trim();
292 }
293
294 private static <T extends Throwable> T findCause(Throwable exception, Class<T> type) {
295 Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
296 for (Throwable t = exception; t != null && dejaVu.add(t); t = t.getCause()) {
297 if (type.isInstance(t)) {
298 return type.cast(t);
299 }
300 }
301 return null;
302 }
303
304 private String join(String message1, String message2) {
305 String message = "";
306
307 if (message1 != null && !message1.isEmpty()) {
308 message = message1.trim();
309 }
310
311 if (message2 != null && !message2.isEmpty()) {
312 if (message != null && !message.isEmpty()) {
313 if (message.endsWith(".") || message.endsWith("!") || message.endsWith(":")) {
314 message += " ";
315 } else {
316 message += ": ";
317 }
318 }
319
320 message += message2;
321 }
322
323 return message;
324 }
325 }