Skip to content

Commit 8debc4a

Browse files
committed
Modify MultitargetException to work with regular dumping/logging mechanisms (dump 'causes' as cause/suppressed exceptions)
1 parent 472f078 commit 8debc4a

File tree

2 files changed

+141
-20
lines changed

2 files changed

+141
-20
lines changed

src/main/java/net/tascalate/concurrent/MultitargetException.java

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
import java.io.IOException;
1919
import java.io.PrintStream;
2020
import java.io.PrintWriter;
21-
21+
import java.io.StringWriter;
2222
import java.util.Collections;
23+
import java.util.IdentityHashMap;
2324
import java.util.List;
2425
import java.util.Objects;
2526
import java.util.Optional;
26-
27+
import java.util.Set;
2728
import java.util.function.BiConsumer;
2829
import java.util.function.Consumer;
30+
import java.util.stream.Collectors;
2931

3032
public class MultitargetException extends Exception {
3133
private final static long serialVersionUID = 1L;
@@ -37,6 +39,25 @@ public MultitargetException(List<Throwable> exceptions) {
3739
Collections.emptyList()
3840
:
3941
Collections.unmodifiableList(exceptions);
42+
List<Throwable> causes = this.exceptions
43+
.stream()
44+
.filter(Objects::nonNull)
45+
.collect(Collectors.toList());
46+
47+
// Need to report back internal details in some standard way
48+
// If there is a single error - then it's the cause
49+
// Otherwie no dedicated cause and a list of suppressed exceptions
50+
switch (causes.size()) {
51+
case 0:
52+
break;
53+
case 1:
54+
initCause(causes.get(0));
55+
break;
56+
default:
57+
for (Throwable cause : causes) {
58+
addSuppressed(cause);
59+
}
60+
}
4061
}
4162

4263
public List<Throwable> getExceptions() {
@@ -52,27 +73,109 @@ public static MultitargetException of(final Throwable exception) {
5273
}
5374

5475
@Override
55-
public void printStackTrace(PrintStream s) {
76+
public String toString() {
77+
return getClass().getName();
78+
}
79+
80+
@Override
81+
public String getMessage() {
82+
StringWriter w = new StringWriter();
83+
printDetails(new PrintWriter(w), newDejavueSet());
84+
return w.toString();
85+
}
86+
87+
void printDetails(PrintWriter w, Set<Throwable> visited) {
88+
visited.add(this);
89+
w.println(toStringSafe());
90+
printExceptions(w, (ex, padding) -> {
91+
PrintWriter pw = new PrintWriter(new PaddedWriter(w, padding), true);
92+
if (visited.contains(ex)) {
93+
String message = ex instanceof MultitargetException ?
94+
((MultitargetException)ex).toStringSafe()
95+
:
96+
ex.toString();
97+
pw.println("\t[CIRCULAR REFERENCE:" + message + "]");
98+
} else {
99+
if (ex instanceof MultitargetException) {
100+
((MultitargetException)ex).printDetails(pw, visited);
101+
} else {
102+
pw.println(ex.toString());
103+
}
104+
}
105+
});
106+
107+
}
108+
109+
public void printExceptions() {
110+
printExceptions(System.err);
111+
}
112+
113+
public void printExceptions(PrintStream s) {
56114
synchronized (s) {
57-
super.printStackTrace(s);
58-
printExceptions(s, (ex, padding) -> {
59-
PrintStream ps = new PrintStream(new PaddedOutputStream(s, padding));
60-
ex.printStackTrace(ps);
61-
});
115+
printExceptions(s, newDejavueSet());
62116
}
63117
}
64118

65-
@Override
66-
public void printStackTrace(PrintWriter w) {
119+
void printExceptions(PrintStream s, Set<Throwable> visited) {
120+
visited.add(this);
121+
122+
//super.printStackTrace(s);
123+
// Print our stack trace
124+
s.println(toStringSafe());
125+
for (StackTraceElement trace : getStackTrace())
126+
s.println("\tat " + trace);
127+
128+
printExceptions(s, (ex, padding) -> {
129+
PrintStream ps = new PrintStream(new PaddedOutputStream(s, padding));
130+
if (visited.contains(ex)) {
131+
String message = ex instanceof MultitargetException ?
132+
((MultitargetException)ex).toStringSafe()
133+
:
134+
ex.toString();
135+
ps.println("\t[CIRCULAR REFERENCE:" + message + "]");
136+
} else {
137+
if (ex instanceof MultitargetException) {
138+
((MultitargetException)ex).printExceptions(ps, visited);
139+
} else {
140+
ex.printStackTrace(ps);
141+
}
142+
}
143+
});
144+
}
145+
146+
public void printExceptions(PrintWriter w) {
67147
synchronized (w) {
68-
super.printStackTrace(w);
69-
printExceptions(w, (ex, padding) -> {
70-
PrintWriter pw = new PrintWriter(new PaddedWriter(w, padding), true);
71-
ex.printStackTrace(pw);
72-
});
148+
printExceptions(w, newDejavueSet());
73149
}
74150
}
75151

152+
void printExceptions(PrintWriter w, Set<Throwable> visited) {
153+
visited.add(this);
154+
155+
//super.printStackTrace(s);
156+
// Print our stack trace
157+
w.println(toStringSafe());
158+
for (StackTraceElement trace : getStackTrace())
159+
w.println("\tat " + trace);
160+
161+
printExceptions(w, (ex, padding) -> {
162+
PrintWriter pw = new PrintWriter(new PaddedWriter(w, padding), true);
163+
if (visited.contains(ex)) {
164+
String message = ex instanceof MultitargetException ?
165+
((MultitargetException)ex).toStringSafe()
166+
:
167+
ex.toString();
168+
pw.println("\t[CIRCULAR REFERENCE:" + message + "]");
169+
} else {
170+
if (ex instanceof MultitargetException) {
171+
((MultitargetException)ex).printExceptions(pw, visited);
172+
} else {
173+
ex.printStackTrace(pw);
174+
}
175+
}
176+
});
177+
}
178+
76179
private <O extends Appendable> void printExceptions(O out, BiConsumer<Throwable, String> nestedExceptionPrinter) {
77180
int idx = 0;
78181
int n = ((int)Math.log10(exceptions.size()) + 1);
@@ -104,5 +207,13 @@ private static <O extends Appendable> void printException(String idx, Throwable
104207
}
105208
}
106209

210+
String toStringSafe() {
211+
return getClass().getName();
212+
}
213+
214+
private static <T> Set<T> newDejavueSet() {
215+
return Collections.newSetFromMap(new IdentityHashMap<T, Boolean>());
216+
}
217+
107218
private static final String NEW_LINE = System.lineSeparator();
108219
}

src/test/java/net/tascalate/concurrent/TestMultitargetExceptionTraces.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
package net.tascalate.concurrent;
22

3+
import java.io.IOException;
34
import java.util.Arrays;
45

56
public class TestMultitargetExceptionTraces {
67

78

89
public static void main(String[] argv) {
9-
Exception e = err();
10+
MultitargetException e = (MultitargetException)err();
11+
//Throwable e = outer().initCause(err());
1012
//e.printStackTrace(new PrintWriter(System.err, true));
1113
e.printStackTrace();
14+
System.out.println("--------------");
15+
System.out.println(e.getLocalizedMessage());
16+
System.out.println("--------------");
17+
e.printExceptions();
18+
}
19+
20+
static Exception outer() {
21+
return new IOException("Invalid user input");
1222
}
1323

1424
static Exception err() {
@@ -23,13 +33,13 @@ static Exception err_1() {
2333
a(), null,
2434
new MultitargetException(Arrays.asList(c(), b()))
2535
));
26-
e.fillInStackTrace();
36+
//e.fillInStackTrace();
2737
return e;
2838
}
2939

3040
static Throwable a() {
3141
Exception e = new IllegalArgumentException("Something wrong", b());
32-
e.fillInStackTrace();
42+
//e.fillInStackTrace();
3343
return e;
3444
}
3545

@@ -43,7 +53,7 @@ static Throwable b_1() {
4353

4454
static Throwable b_2() {
4555
Throwable e = new NoSuchMethodError("Data not found");
46-
e.fillInStackTrace();
56+
//e.fillInStackTrace();
4757
return e;
4858
}
4959

@@ -57,7 +67,7 @@ static Throwable c_1() {
5767

5868
static Exception c_2() {
5969
Exception e = new IllegalStateException("State is forbidden");
60-
e.fillInStackTrace();
70+
//e.fillInStackTrace();
6171
return e;
6272
}
6373

0 commit comments

Comments
 (0)