You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/05/05 21:22:54 UTC

[commons-lang] branch master updated: [LANG-1457] Add ExceptionUtils.throwableOfType(Throwable, Class) and friends.

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 <ga...@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
         }
     }