This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push: new 1ec6c0a [LANG-1457] Add ExceptionUtils.throwableOfType(Throwable, Class) and friends. 1ec6c0a is described below commit 1ec6c0ae9a28ef0d1a10adbded66d2b00ea840d4 Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Sun May 5 17:22:45 2019 -0400 [LANG-1457] Add ExceptionUtils.throwableOfType(Throwable, Class) and friends. --- src/changes/changes.xml | 1 + .../commons/lang3/exception/ExceptionUtils.java | 145 +++++++++++++++++++-- .../lang3/exception/ExceptionUtilsTest.java | 112 +++++++++++++++- 3 files changed, 248 insertions(+), 10 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 7ef4c18..e59d33a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -47,6 +47,7 @@ The <action> type attribute can be add,update,fix,remove. <release version="3.10" date="YYYY-MM-DD" description="TBD"> <action issue="LANG-1450" type="fix" dev="chtompki">Generate javadoc jar on build.</action> + <action issue="LANG-1457" type="fix" dev="ggregory">Add ExceptionUtils.throwableOfType(Throwable, Class) and friends.</action> </release> <release version="3.9" date="2019-04-09" description="New features and bug fixes. Requires Java 8, supports Java 9, 10, 11"> diff --git a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java index 52d0c87..4d0f040 100644 --- a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java +++ b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java @@ -285,9 +285,8 @@ public class ExceptionUtils { return list; } - //----------------------------------------------------------------------- /** - * <p>Returns the (zero based) index of the first <code>Throwable</code> + * <p>Returns the (zero-based) index of the first <code>Throwable</code> * that matches the specified class (exactly) in the exception chain. * Subclasses of the specified class do not match - see * {@link #indexOfType(Throwable, Class)} for the opposite.</p> @@ -305,7 +304,27 @@ public class ExceptionUtils { } /** - * <p>Returns the (zero based) index of the first <code>Throwable</code> + * <p>Returns the first <code>Throwable</code> + * that matches the specified class (exactly) in the exception chain. + * Subclasses of the specified class do not match - see + * {@link #throwableOfType(Throwable, Class)} for the opposite.</p> + * + * <p>A <code>null</code> throwable returns <code>null</code>. + * A <code>null</code> type returns <code>null</code>. + * No match in the chain returns <code>null</code>.</p> + * + * @param <T> the type of Throwable you are searching. + * @param throwable the throwable to inspect, may be null + * @param clazz the class to search for, subclasses do not match, null returns null + * @return the index into the throwable chain, null if no match or null input + * @since 3.10 + */ + public static <T extends Throwable> T throwableOfThrowable(final Throwable throwable, final Class<T> clazz) { + return throwableOf(throwable, clazz, 0, false); + } + + /** + * <p>Returns the (zero-based) index of the first <code>Throwable</code> * that matches the specified type in the exception chain from * a specified index. * Subclasses of the specified class do not match - see @@ -319,7 +338,7 @@ public class ExceptionUtils { * * @param throwable the throwable to inspect, may be null * @param clazz the class to search for, subclasses do not match, null returns -1 - * @param fromIndex the (zero based) index of the starting position, + * @param fromIndex the (zero-based) index of the starting position, * negative treated as zero, larger than chain size returns -1 * @return the index into the throwable chain, -1 if no match or null input */ @@ -327,9 +346,33 @@ public class ExceptionUtils { return indexOf(throwable, clazz, fromIndex, false); } - //----------------------------------------------------------------------- /** - * <p>Returns the (zero based) index of the first <code>Throwable</code> + * <p>Returns the first <code>Throwable</code> + * that matches the specified type in the exception chain from + * a specified index. + * Subclasses of the specified class do not match - see + * {@link #throwableOfType(Throwable, Class, int)} for the opposite.</p> + * + * <p>A <code>null</code> throwable returns <code>null</code>. + * A <code>null</code> type returns <code>null</code>. + * No match in the chain returns <code>null</code>. + * A negative start index is treated as zero. + * A start index greater than the number of throwables returns <code>null</code>.</p> + * + * @param <T> the type of Throwable you are searching. + * @param throwable the throwable to inspect, may be null + * @param clazz the class to search for, subclasses do not match, null returns null + * @param fromIndex the (zero-based) index of the starting position, + * negative treated as zero, larger than chain size returns null + * @return the index into the throwable chain, null if no match or null input + * @since 3.10 + */ + public static <T extends Throwable> T throwableOfThrowable(final Throwable throwable, final Class<T> clazz, final int fromIndex) { + return throwableOf(throwable, clazz, fromIndex, false); + } + + /** + * <p>Returns the (zero-based) index of the first <code>Throwable</code> * that matches the specified class or subclass in the exception chain. * Subclasses of the specified class do match - see * {@link #indexOfThrowable(Throwable, Class)} for the opposite.</p> @@ -348,7 +391,52 @@ public class ExceptionUtils { } /** - * <p>Returns the (zero based) index of the first <code>Throwable</code> + * <p>Returns the throwable of the first <code>Throwable</code> + * that matches the specified class or subclass in the exception chain. + * Subclasses of the specified class do match - see + * {@link #throwableOfThrowable(Throwable, Class)} for the opposite..</p> + * + * <p>A <code>null</code> throwable returns <code>null</code>. + * A <code>null</code> type returns <code>null</code>. + * No match in the chain returns <code>null</code>.</p> + * + * @param <T> the type of Throwable you are searching. + * @param throwable the throwable to inspect, may be null + * @param type the type to search for, subclasses match, null returns null + * @return the index into the throwable chain, null if no match or null input + * @since 3.10 + */ + public static <T extends Throwable> T throwableOfType(final Throwable throwable, final Class<T> type) { + return throwableOf(throwable, type, 0, true); + } + + /** + * <p>Returns the first <code>Throwable</code> + * that matches the specified type in the exception chain from + * a specified index. + * Subclasses of the specified class do match - see + * {@link #throwableOfThrowable(Throwable, Class)} for the opposite.</p> + * + * <p>A <code>null</code> throwable returns <code>null</code>. + * A <code>null</code> type returns <code>null</code>. + * No match in the chain returns <code>null</code>. + * A negative start index is treated as zero. + * A start index greater than the number of throwables returns <code>null</code>.</p> + * + * @param <T> the type of Throwable you are searching. + * @param throwable the throwable to inspect, may be null + * @param type the type to search for, subclasses match, null returns null + * @param fromIndex the (zero-based) index of the starting position, + * negative treated as zero, larger than chain size returns null + * @return the index into the throwable chain, null if no match or null input + * @since 3.10 + */ + public static <T extends Throwable> T throwableOfType(final Throwable throwable, final Class<T> type, final int fromIndex) { + return throwableOf(throwable, type, fromIndex, true); + } + + /** + * <p>Returns the (zero-based) index of the first <code>Throwable</code> * that matches the specified type in the exception chain from * a specified index. * Subclasses of the specified class do match - see @@ -362,7 +450,7 @@ public class ExceptionUtils { * * @param throwable the throwable to inspect, may be null * @param type the type to search for, subclasses match, null returns -1 - * @param fromIndex the (zero based) index of the starting position, + * @param fromIndex the (zero-based) index of the starting position, * negative treated as zero, larger than chain size returns -1 * @return the index into the throwable chain, -1 if no match or null input * @since 2.1 @@ -376,7 +464,7 @@ public class ExceptionUtils { * * @param throwable the throwable to inspect, may be null * @param type the type to search for, subclasses match, null returns -1 - * @param fromIndex the (zero based) index of the starting position, + * @param fromIndex the (zero-based) index of the starting position, * negative treated as zero, larger than chain size returns -1 * @param subclass if <code>true</code>, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares * using references @@ -409,6 +497,45 @@ public class ExceptionUtils { return -1; } + /** + * <p>Worker method for the <code>throwableOfType</code> methods.</p> + * + * @param <T> the type of Throwable you are searching. + * @param throwable the throwable to inspect, may be null + * @param type the type to search, subclasses match, null returns null + * @param fromIndex the (zero-based) index of the starting position, + * negative treated as zero, larger than chain size returns null + * @param subclass if <code>true</code>, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares + * using references + * @return throwable of the <code>type</code> within throwables nested within the specified <code>throwable</code> + */ + private static <T extends Throwable> T throwableOf(final Throwable throwable, final Class<T> type, int fromIndex, final boolean subclass) { + if (throwable == null || type == null) { + return null; + } + if (fromIndex < 0) { + fromIndex = 0; + } + final Throwable[] throwables = getThrowables(throwable); + if (fromIndex >= throwables.length) { + return null; + } + if (subclass) { + for (int i = fromIndex; i < throwables.length; i++) { + if (type.isAssignableFrom(throwables[i].getClass())) { + return type.cast(throwables[i]); + } + } + } else { + for (int i = fromIndex; i < throwables.length; i++) { + if (type.equals(throwables[i].getClass())) { + return type.cast(throwables[i]); + } + } + } + return null; + } + //----------------------------------------------------------------------- /** * <p>Prints a compact stack trace for the root cause of a throwable diff --git a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java index 035b0b8..ad57dcb 100644 --- a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java @@ -258,7 +258,6 @@ public class ExceptionUtilsTest { assertSame(cyclicCause.getCause().getCause(), throwables.get(2)); } - //----------------------------------------------------------------------- @Test public void testIndexOf_ThrowableClass() { assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null)); @@ -280,6 +279,31 @@ public class ExceptionUtilsTest { assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class)); assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class)); + assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class)); + } + + @Test + public void testThrowableOf_ThrowableClass() { + assertEquals(null, ExceptionUtils.throwableOfThrowable(null, null)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(null, NestableException.class)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, null)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class)); + assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(nested, null)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class)); + assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class)); + assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, null)); + assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class)); + assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class)); + assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, Exception.class)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, Throwable.class)); } @Test @@ -308,6 +332,36 @@ public class ExceptionUtilsTest { assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 9)); assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class, 0)); + assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Throwable.class, 0)); + } + + @Test + public void testThrowableOf_ThrowableClassInt() { + assertEquals(null, ExceptionUtils.throwableOfThrowable(null, null, 0)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(null, NestableException.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, null)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithCause.class, 0)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withoutCause, NestableException.class, 0)); + assertEquals(withoutCause, ExceptionUtils.throwableOfThrowable(withoutCause, ExceptionWithoutCause.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(nested, null, 0)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(nested, ExceptionWithCause.class, 0)); + assertEquals(nested, ExceptionUtils.throwableOfThrowable(nested, NestableException.class, 0)); + assertEquals(nested.getCause(), ExceptionUtils.throwableOfThrowable(nested, ExceptionWithoutCause.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, null)); + assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0)); + assertEquals(withCause.getCause(), ExceptionUtils.throwableOfThrowable(withCause, NestableException.class, 0)); + assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithoutCause.class, 0)); + + assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, -1)); + assertEquals(withCause, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 0)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 1)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, ExceptionWithCause.class, 9)); + + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, Exception.class, 0)); + assertEquals(null, ExceptionUtils.throwableOfThrowable(withCause, Throwable.class, 0)); } //----------------------------------------------------------------------- @@ -332,6 +386,31 @@ public class ExceptionUtilsTest { assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class)); assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class)); + assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class)); + } + + @Test + public void testThrowableOfType_ThrowableClass() { + assertEquals(null, ExceptionUtils.throwableOfType(null, null)); + assertEquals(null, ExceptionUtils.throwableOfType(null, NestableException.class)); + + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, null)); + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class)); + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, NestableException.class)); + assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class)); + + assertEquals(null, ExceptionUtils.throwableOfType(nested, null)); + assertEquals(null, ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class)); + assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class)); + assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class)); + + assertEquals(null, ExceptionUtils.throwableOfType(withCause, null)); + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class)); + assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class)); + assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class)); + + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class)); + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class)); } @Test @@ -360,6 +439,36 @@ public class ExceptionUtilsTest { assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 9)); assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class, 0)); + assertEquals(0, ExceptionUtils.indexOfType(withCause, Throwable.class, 0)); + } + + @Test + public void testThrowableOfType_ThrowableClassInt() { + assertEquals(null, ExceptionUtils.throwableOfType(null, null, 0)); + assertEquals(null, ExceptionUtils.throwableOfType(null, NestableException.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, null)); + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithCause.class, 0)); + assertEquals(null, ExceptionUtils.throwableOfType(withoutCause, NestableException.class, 0)); + assertEquals(withoutCause, ExceptionUtils.throwableOfType(withoutCause, ExceptionWithoutCause.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfType(nested, null, 0)); + assertEquals(null, ExceptionUtils.throwableOfType(nested, ExceptionWithCause.class, 0)); + assertEquals(nested, ExceptionUtils.throwableOfType(nested, NestableException.class, 0)); + assertEquals(nested.getCause(), ExceptionUtils.throwableOfType(nested, ExceptionWithoutCause.class, 0)); + + assertEquals(null, ExceptionUtils.throwableOfType(withCause, null)); + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0)); + assertEquals(withCause.getCause(), ExceptionUtils.throwableOfType(withCause, NestableException.class, 0)); + assertEquals(withCause.getCause().getCause(), ExceptionUtils.throwableOfType(withCause, ExceptionWithoutCause.class, 0)); + + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, -1)); + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 0)); + assertEquals(null, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 1)); + assertEquals(null, ExceptionUtils.throwableOfType(withCause, ExceptionWithCause.class, 9)); + + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Exception.class, 0)); + assertEquals(withCause, ExceptionUtils.throwableOfType(withCause, Throwable.class, 0)); } //----------------------------------------------------------------------- @@ -516,6 +625,7 @@ public class ExceptionUtilsTest { @SuppressWarnings("unused") public void getTargetException() { + // noop } }