1 package org.codehaus.plexus.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 import java.io.PrintStream;
58 import java.io.PrintWriter;
59 import java.io.StringWriter;
60 import java.lang.reflect.Field;
61 import java.lang.reflect.InvocationTargetException;
62 import java.lang.reflect.Method;
63 import java.sql.SQLException;
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.LinkedList;
67 import java.util.List;
68 import java.util.StringTokenizer;
69
70
71
72
73
74
75
76
77
78
79
80
81 public class ExceptionUtils {
82
83
84
85
86 static final String WRAPPED_MARKER = " [wrapped] ";
87
88
89
90
91 protected static String[] CAUSE_METHOD_NAMES = {
92 "getCause",
93 "getNextException",
94 "getTargetException",
95 "getException",
96 "getSourceException",
97 "getRootCause",
98 "getCausedByException",
99 "getNested"
100 };
101
102
103
104
105 protected ExceptionUtils() {}
106
107
108
109
110
111
112
113
114 public static void addCauseMethodName(String methodName) {
115 if (methodName != null && methodName.length() > 0) {
116 List<String> list = new ArrayList<String>(Arrays.asList(CAUSE_METHOD_NAMES));
117 list.add(methodName);
118 CAUSE_METHOD_NAMES = list.toArray(new String[0]);
119 }
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 public static Throwable getCause(Throwable throwable) {
154 return getCause(throwable, CAUSE_METHOD_NAMES);
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168 public static Throwable getCause(Throwable throwable, String[] methodNames) {
169 Throwable cause = getCauseUsingWellKnownTypes(throwable);
170 if (cause == null) {
171 for (String methodName : methodNames) {
172 cause = getCauseUsingMethodName(throwable, methodName);
173 if (cause != null) {
174 break;
175 }
176 }
177
178 if (cause == null) {
179 cause = getCauseUsingFieldName(throwable, "detail");
180 }
181 }
182 return cause;
183 }
184
185
186
187
188
189
190
191
192
193
194 public static Throwable getRootCause(Throwable throwable) {
195 Throwable cause = getCause(throwable);
196 if (cause != null) {
197 throwable = cause;
198 while ((throwable = getCause(throwable)) != null) {
199 cause = throwable;
200 }
201 }
202 return cause;
203 }
204
205
206
207
208
209
210
211
212
213
214 private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
215 if (throwable instanceof SQLException) {
216 return ((SQLException) throwable).getNextException();
217 } else if (throwable instanceof InvocationTargetException) {
218 return ((InvocationTargetException) throwable).getTargetException();
219 } else {
220 return null;
221 }
222 }
223
224
225
226
227
228
229
230
231
232
233 private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
234 Method method = null;
235 try {
236 method = throwable.getClass().getMethod(methodName, null);
237 } catch (NoSuchMethodException ignored) {
238 } catch (SecurityException ignored) {
239 }
240
241 if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
242 try {
243 return (Throwable) method.invoke(throwable, new Object[0]);
244 } catch (IllegalAccessException ignored) {
245 } catch (IllegalArgumentException ignored) {
246 } catch (InvocationTargetException ignored) {
247 }
248 }
249 return null;
250 }
251
252
253
254
255
256
257
258
259
260
261 private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) {
262 Field field = null;
263 try {
264 field = throwable.getClass().getField(fieldName);
265 } catch (NoSuchFieldException ignored) {
266 } catch (SecurityException ignored) {
267 }
268
269 if (field != null && Throwable.class.isAssignableFrom(field.getType())) {
270 try {
271 return (Throwable) field.get(throwable);
272 } catch (IllegalAccessException ignored) {
273 } catch (IllegalArgumentException ignored) {
274 }
275 }
276 return null;
277 }
278
279
280
281
282
283
284
285
286
287 public static int getThrowableCount(Throwable throwable) {
288
289 int count = 0;
290 while (throwable != null) {
291 count++;
292 throwable = ExceptionUtils.getCause(throwable);
293 }
294 return count;
295 }
296
297
298
299
300
301
302
303
304
305 public static Throwable[] getThrowables(Throwable throwable) {
306 List<Throwable> list = new ArrayList<>();
307 while (throwable != null) {
308 list.add(throwable);
309 throwable = getCause(throwable);
310 }
311 return list.toArray(new Throwable[0]);
312 }
313
314
315
316
317
318
319
320
321
322
323
324 public static int indexOfThrowable(Throwable throwable, Class type) {
325 return indexOfThrowable(throwable, type, 0);
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 public static int indexOfThrowable(Throwable throwable, Class type, int fromIndex) {
343 if (fromIndex < 0) {
344 throw new IndexOutOfBoundsException("Throwable index out of range: " + fromIndex);
345 }
346 Throwable[] throwables = ExceptionUtils.getThrowables(throwable);
347 if (fromIndex >= throwables.length) {
348 throw new IndexOutOfBoundsException("Throwable index out of range: " + fromIndex);
349 }
350 for (int i = fromIndex; i < throwables.length; i++) {
351 if (throwables[i].getClass().equals(type)) {
352 return i;
353 }
354 }
355 return -1;
356 }
357
358
359
360
361
362
363
364
365
366
367 public static void printRootCauseStackTrace(Throwable t, PrintStream stream) {
368 String trace[] = getRootCauseStackTrace(t);
369 for (String aTrace : trace) {
370 stream.println(aTrace);
371 }
372 stream.flush();
373 }
374
375
376
377
378
379 public static void printRootCauseStackTrace(Throwable t) {
380 printRootCauseStackTrace(t, System.err);
381 }
382
383
384
385
386
387
388 public static void printRootCauseStackTrace(Throwable t, PrintWriter writer) {
389 String trace[] = getRootCauseStackTrace(t);
390 for (String aTrace : trace) {
391 writer.println(aTrace);
392 }
393 writer.flush();
394 }
395
396
397
398
399
400
401
402 public static String[] getRootCauseStackTrace(Throwable t) {
403 Throwable[] throwables = getThrowables(t);
404 int count = throwables.length;
405 ArrayList<String> frames = new ArrayList<>();
406 List<String> nextTrace = getStackFrameList(throwables[count - 1]);
407 for (int i = count; --i >= 0; ) {
408 List<String> trace = nextTrace;
409 if (i != 0) {
410 nextTrace = getStackFrameList(throwables[i - 1]);
411 removeCommonFrames(trace, nextTrace);
412 }
413 if (i == (count - 1)) {
414 frames.add(throwables[i].toString());
415 } else {
416 frames.add(WRAPPED_MARKER + throwables[i].toString());
417 }
418 for (String aTrace : trace) {
419 frames.add(aTrace);
420 }
421 }
422 return frames.toArray(new String[0]);
423 }
424
425
426
427
428
429
430
431 private static void removeCommonFrames(List<String> causeFrames, List<String> wrapperFrames) {
432 int causeFrameIndex = causeFrames.size() - 1;
433 int wrapperFrameIndex = wrapperFrames.size() - 1;
434 while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
435
436
437 String causeFrame = causeFrames.get(causeFrameIndex);
438 String wrapperFrame = wrapperFrames.get(wrapperFrameIndex);
439 if (causeFrame.equals(wrapperFrame)) {
440 causeFrames.remove(causeFrameIndex);
441 }
442 causeFrameIndex--;
443 wrapperFrameIndex--;
444 }
445 }
446
447
448
449
450
451
452
453 public static String getStackTrace(Throwable t) {
454 StringWriter sw = new StringWriter();
455 PrintWriter pw = new PrintWriter(sw, true);
456 t.printStackTrace(pw);
457 return sw.getBuffer().toString();
458 }
459
460
461
462
463
464
465
466 public static String getFullStackTrace(Throwable t) {
467 StringWriter sw = new StringWriter();
468 PrintWriter pw = new PrintWriter(sw, true);
469 Throwable[] ts = getThrowables(t);
470 for (Throwable t1 : ts) {
471 t1.printStackTrace(pw);
472 if (isNestedThrowable(t1)) {
473 break;
474 }
475 }
476 return sw.getBuffer().toString();
477 }
478
479
480
481
482
483
484
485 public static boolean isNestedThrowable(Throwable throwable) {
486 if (throwable == null) {
487 return false;
488 }
489
490 if (throwable instanceof SQLException) {
491 return true;
492 } else if (throwable instanceof InvocationTargetException) {
493 return true;
494 }
495
496 for (String CAUSE_METHOD_NAME : CAUSE_METHOD_NAMES) {
497 try {
498 Method method = throwable.getClass().getMethod(CAUSE_METHOD_NAME, null);
499 if (method != null) {
500 return true;
501 }
502 } catch (NoSuchMethodException ignored) {
503 } catch (SecurityException ignored) {
504 }
505 }
506
507 try {
508 Field field = throwable.getClass().getField("detail");
509 if (field != null) {
510 return true;
511 }
512 } catch (NoSuchFieldException ignored) {
513 } catch (SecurityException ignored) {
514 }
515
516 return false;
517 }
518
519
520
521
522
523
524
525
526 public static String[] getStackFrames(Throwable t) {
527 return getStackFrames(getStackTrace(t));
528 }
529
530
531
532
533 static String[] getStackFrames(String stackTrace) {
534 String linebreak = System.getProperty("line.separator");
535 StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
536 List<String> list = new LinkedList<String>();
537 while (frames.hasMoreTokens()) {
538 list.add(frames.nextToken());
539 }
540 return list.toArray(new String[0]);
541 }
542
543
544
545
546
547
548
549
550 static List<String> getStackFrameList(Throwable t) {
551 String stackTrace = getStackTrace(t);
552 String linebreak = System.getProperty("line.separator");
553 StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
554 List<String> list = new LinkedList<String>();
555 boolean traceStarted = false;
556 while (frames.hasMoreTokens()) {
557 String token = frames.nextToken();
558
559 int at = token.indexOf("at");
560 if (at != -1 && token.substring(0, at).trim().length() == 0) {
561 traceStarted = true;
562 list.add(token);
563 } else if (traceStarted) {
564 break;
565 }
566 }
567 return list;
568 }
569 }