Skip to content

Commit 267d569

Browse files
Merge pull request #805 from benjchristensen/fix-composite-exception
Fix CompositeException
2 parents de1e0b1 + a98b17d commit 267d569

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

rxjava-core/src/main/java/rx/util/CompositeException.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import java.util.ArrayList;
1919
import java.util.Collection;
2020
import java.util.Collections;
21+
import java.util.HashSet;
2122
import java.util.List;
23+
import java.util.Set;
2224

2325
/**
2426
* Exception that is a composite of 1 or more other exceptions.
@@ -84,9 +86,16 @@ private static String getStackTraceAsString(StackTraceElement[] stack) {
8486
return s.toString();
8587
}
8688

87-
private static void attachCallingThreadStack(Throwable e, Throwable cause) {
89+
/* package-private */ static void attachCallingThreadStack(Throwable e, Throwable cause) {
90+
Set<Throwable> seenCauses = new HashSet<Throwable>();
91+
8892
while (e.getCause() != null) {
8993
e = e.getCause();
94+
if (seenCauses.contains(e.getCause())) {
95+
break;
96+
} else {
97+
seenCauses.add(e.getCause());
98+
}
9099
}
91100
// we now have 'e' as the last in the chain
92101
try {
@@ -98,12 +107,13 @@ private static void attachCallingThreadStack(Throwable e, Throwable cause) {
98107
}
99108
}
100109

101-
private final static class CompositeExceptionCausalChain extends RuntimeException {
110+
/* package-private */ final static class CompositeExceptionCausalChain extends RuntimeException {
102111
private static final long serialVersionUID = 3875212506787802066L;
112+
/* package-private */ static String MESSAGE = "Chain of Causes for CompositeException In Order Received =>";
103113

104114
@Override
105115
public String getMessage() {
106-
return "Chain of Causes for CompositeException In Order Received =>";
116+
return MESSAGE;
107117
}
108118
}
109119

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* Copyright 2013 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.util;
17+
18+
import static org.junit.Assert.*;
19+
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.List;
23+
24+
import org.junit.Test;
25+
26+
public class CompositeExceptionTest {
27+
28+
private final Throwable ex1 = new Throwable("Ex1");
29+
private final Throwable ex2 = new Throwable("Ex2", ex1);
30+
private final Throwable ex3 = new Throwable("Ex3", ex2);
31+
32+
public CompositeExceptionTest() {
33+
ex1.initCause(ex2);
34+
}
35+
36+
private CompositeException getNewCompositeExceptionWithEx123() {
37+
List<Throwable> throwables = new ArrayList<Throwable>();
38+
throwables.add(ex1);
39+
throwables.add(ex2);
40+
throwables.add(ex3);
41+
return new CompositeException(throwables);
42+
}
43+
44+
@Test(timeout = 1000)
45+
public void testMultipleWithSameCause() {
46+
Throwable rootCause = new Throwable("RootCause");
47+
Throwable e1 = new Throwable("1", rootCause);
48+
Throwable e2 = new Throwable("2", rootCause);
49+
Throwable e3 = new Throwable("3", rootCause);
50+
CompositeException ce = new CompositeException("3 failures with same root cause", Arrays.asList(e1, e2, e3));
51+
}
52+
53+
@Test(timeout = 1000)
54+
public void testAttachCallingThreadStackParentThenChild() {
55+
CompositeException.attachCallingThreadStack(ex1, ex2);
56+
assertEquals("Ex2", ex1.getCause().getMessage());
57+
}
58+
59+
@Test(timeout = 1000)
60+
public void testAttachCallingThreadStackChildThenParent() {
61+
CompositeException.attachCallingThreadStack(ex2, ex1);
62+
assertEquals("Ex1", ex2.getCause().getMessage());
63+
}
64+
65+
@Test(timeout = 1000)
66+
public void testAttachCallingThreadStackAddComposite() {
67+
CompositeException.attachCallingThreadStack(ex1, getNewCompositeExceptionWithEx123());
68+
assertEquals("Ex2", ex1.getCause().getMessage());
69+
}
70+
71+
@Test(timeout = 1000)
72+
public void testAttachCallingThreadStackAddToComposite() {
73+
CompositeException compositeEx = getNewCompositeExceptionWithEx123();
74+
CompositeException.attachCallingThreadStack(compositeEx, ex1);
75+
assertEquals(CompositeException.CompositeExceptionCausalChain.MESSAGE, compositeEx.getCause().getMessage());
76+
}
77+
78+
@Test(timeout = 1000)
79+
public void testAttachCallingThreadStackAddCompositeToItself() {
80+
CompositeException compositeEx = getNewCompositeExceptionWithEx123();
81+
CompositeException.attachCallingThreadStack(compositeEx, compositeEx);
82+
assertEquals(CompositeException.CompositeExceptionCausalChain.MESSAGE, compositeEx.getCause().getMessage());
83+
}
84+
85+
@Test(timeout = 1000)
86+
public void testAttachCallingThreadStackAddExceptionsToEachOther() {
87+
CompositeException.attachCallingThreadStack(ex1, ex2);
88+
CompositeException.attachCallingThreadStack(ex2, ex1);
89+
assertEquals("Ex2", ex1.getCause().getMessage());
90+
assertEquals("Ex1", ex2.getCause().getMessage());
91+
}
92+
}

0 commit comments

Comments
 (0)