Add ExceptionUtils.forEach(Throwable, Consumer<Throwable>)
Add ExceptionUtils.stream(Throwable).
This commit is contained in:
parent
7912894eb8
commit
70b2250f80
|
@ -147,6 +147,8 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
<action type="add" dev="ggregory" due-to="Gary Gregory">Add coverage.yml.</action>
|
||||
<action type="add" dev="ggregory" due-to="Gary Gregory">Add DurationUtils.since(Temporal).</action>
|
||||
<action type="add" dev="ggregory" due-to="Gary Gregory">Add DurationUtils.of(FailableConsumer|FailableRunnbale).</action>
|
||||
<action type="add" dev="ggregory" due-to="Gary Gregory">Add ExceptionUtils.forEach(Throwable, Consumer<Throwable>).</action>
|
||||
<action type="add" dev="ggregory" due-to="Gary Gregory">Add ExceptionUtils.stream(Throwable).</action>
|
||||
<!-- UPDATE -->
|
||||
<action type="update" dev="ggregory" due-to="Dependabot, XenoAmess, Gary Gregory">Bump actions/cache from 2.1.4 to 3.0.4 #742, #752, #764, #833, #867.</action>
|
||||
<action type="update" dev="ggregory" due-to="Dependabot">Bump actions/checkout from 2 to 3 #819, #825, #859.</action>
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
@ -427,6 +429,26 @@ public class ExceptionUtils {
|
|||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an action for each Throwable causes of the given Throwable.
|
||||
* <p>
|
||||
* A throwable without cause will return a stream containing one element - the input throwable. A throwable with one cause
|
||||
* will return a stream containing two elements. - the input throwable and the cause throwable. A {@code null} throwable
|
||||
* will return a stream of count zero.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method handles recursive cause structures that might otherwise cause infinite loops. The cause chain is
|
||||
* processed until the end is reached, or until the next item in the chain is already in the result set.
|
||||
* </p>
|
||||
* @param throwable The Throwable to traverse.
|
||||
* @param consumer a non-interfering action to perform on the elements.
|
||||
* @since 3.13.0
|
||||
*/
|
||||
public static void forEach(final Throwable throwable, final Consumer<Throwable> consumer) {
|
||||
stream(throwable).forEach(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of {@code Throwable} objects in the
|
||||
* exception chain.
|
||||
|
@ -770,6 +792,28 @@ public class ExceptionUtils {
|
|||
return ExceptionUtils.<R, RuntimeException>eraseType(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams causes of a Throwable.
|
||||
* <p>
|
||||
* A throwable without cause will return a stream containing one element - the input throwable. A throwable with one cause
|
||||
* will return a stream containing two elements. - the input throwable and the cause throwable. A {@code null} throwable
|
||||
* will return a stream of count zero.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method handles recursive cause structures that might otherwise cause infinite loops. The cause chain is
|
||||
* processed until the end is reached, or until the next item in the chain is already in the result set.
|
||||
* </p>
|
||||
*
|
||||
* @param throwable The Throwable to traverse
|
||||
* @return A new Stream of Throwable causes.
|
||||
* @since 3.13.0
|
||||
*/
|
||||
public static Stream<Throwable> stream(final Throwable throwable) {
|
||||
// No point building a custom Iterable as it would keep track of visited elements to avoid infinite loops
|
||||
return getThrowableList(throwable).stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Worker method for the {@code throwableOfType} methods.
|
||||
*
|
||||
|
|
|
@ -32,7 +32,9 @@ import java.io.PrintWriter;
|
|||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.test.NotVisibleExceptionFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -216,6 +218,58 @@ public class ExceptionUtilsTest {
|
|||
assertFalse(Modifier.isFinal(ExceptionUtils.class.getModifiers()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_jdkNoCause() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(jdkNoCause, throwables::add);
|
||||
assertEquals(1, throwables.size());
|
||||
assertSame(jdkNoCause, throwables.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_nested() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(nested, throwables::add);
|
||||
assertEquals(2, throwables.size());
|
||||
assertSame(nested, throwables.get(0));
|
||||
assertSame(withoutCause, throwables.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_null() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(null, throwables::add);
|
||||
assertEquals(0, throwables.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_recursiveCause() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(cyclicCause, throwables::add);
|
||||
assertEquals(3, throwables.size());
|
||||
assertSame(cyclicCause, throwables.get(0));
|
||||
assertSame(cyclicCause.getCause(), throwables.get(1));
|
||||
assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_withCause() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(withCause, throwables::add);
|
||||
assertEquals(3, throwables.size());
|
||||
assertSame(withCause, throwables.get(0));
|
||||
assertSame(nested, throwables.get(1));
|
||||
assertSame(withoutCause, throwables.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_withoutCause() {
|
||||
final List<Throwable> throwables = new ArrayList<>();
|
||||
ExceptionUtils.forEach(withoutCause, throwables::add);
|
||||
assertEquals(1, throwables.size());
|
||||
assertSame(withoutCause, throwables.get(0));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Specifically tests the deprecated methods
|
||||
@Test
|
||||
public void testGetCause_Throwable() {
|
||||
|
@ -497,7 +551,6 @@ public class ExceptionUtilsTest {
|
|||
assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexOfType_ThrowableClassInt() {
|
||||
assertEquals(-1, ExceptionUtils.indexOfType(null, null, 0));
|
||||
|
@ -587,6 +640,50 @@ public class ExceptionUtilsTest {
|
|||
assertThrows(IllegalArgumentException.class, () -> ExceptionUtils.removeCommonFrames(null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_jdkNoCause() {
|
||||
assertEquals(1, ExceptionUtils.stream(jdkNoCause).count());
|
||||
assertSame(jdkNoCause, ExceptionUtils.stream(jdkNoCause).toArray()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_nested() {
|
||||
assertEquals(2, ExceptionUtils.stream(nested).count());
|
||||
final Object[] array = ExceptionUtils.stream(nested).toArray();
|
||||
assertSame(nested, array[0]);
|
||||
assertSame(withoutCause, array[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_null() {
|
||||
assertEquals(0, ExceptionUtils.stream(null).count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_recursiveCause() {
|
||||
final List<?> throwables = ExceptionUtils.stream(cyclicCause).collect(Collectors.toList());
|
||||
assertEquals(3, throwables.size());
|
||||
assertSame(cyclicCause, throwables.get(0));
|
||||
assertSame(cyclicCause.getCause(), throwables.get(1));
|
||||
assertSame(cyclicCause.getCause().getCause(), throwables.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_withCause() {
|
||||
final List<?> throwables = ExceptionUtils.stream(withCause).collect(Collectors.toList());
|
||||
assertEquals(3, throwables.size());
|
||||
assertSame(withCause, throwables.get(0));
|
||||
assertSame(nested, throwables.get(1));
|
||||
assertSame(withoutCause, throwables.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStream_withoutCause() {
|
||||
final List<?> throwables = ExceptionUtils.stream(withoutCause).collect(Collectors.toList());
|
||||
assertEquals(1, throwables.size());
|
||||
assertSame(withoutCause, throwables.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrow() {
|
||||
final Exception expected = new InterruptedException();
|
||||
|
|
Loading…
Reference in New Issue