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

commit 3935fa2f193a0cc652300677beeb61b535eedf4c
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Tue Oct 17 11:16:29 2023 -0400

    Add ExceptionUtils.asRuntimeException(T), and deprecate rethrow(T)
---
 src/changes/changes.xml                            |  1 +
 .../commons/lang3/exception/ExceptionUtils.java    | 82 +++++++++++++++++++---
 .../apache/commons/lang3/time/FastDatePrinter.java |  2 +-
 .../lang3/exception/ExceptionUtilsTest.java        | 12 +++-
 4 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index acfd3a581..3dbc096f0 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -75,6 +75,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add FailableSupplier.nul().</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add Suppliers.nul().</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add ExceptionUtils.throwUnchecked(T) where T extends Throwable, and 
deprecate Object version.</action>
+    <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add ExceptionUtils.rethrowRuntimeException(T), and deprecate 
rethrow(T).</action>
     <!-- UPDATE -->
     <action                   type="update" dev="ggregory" due-to="Gary 
Gregory">Bump commons-parent from 58 to 64.</action>
     <action                   type="update" dev="ggregory" due-to="Gary 
Gregory">Bump org.easymock:easymock from 5.1.0 to 5.2.0 #1104.</action>
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 57bfe286f..69f4f6ccf 100644
--- a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
+++ b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
@@ -71,6 +71,69 @@ public class ExceptionUtils {
      */
     static final String WRAPPED_MARKER = " [wrapped] ";
 
+    /**
+     * Use to throws a checked exception without adding the exception to the 
throws
+     * clause of the calling method. This method prevents throws clause
+     * pollution and reduces the clutter of "Caused by" exceptions in the
+     * stack trace.
+     * <p>
+     * The use of this technique may be controversial, but exceedingly useful 
to
+     * library developers.
+     * </p>
+     * <pre>
+     *  public int propagateExample { // note that there is no throws clause
+     *      try {
+     *          return invocation(); // throws IOException
+     *      } catch (Exception e) {
+     *          return ExceptionUtils.rethrowRuntimeException(e);  // 
propagates a checked exception
+     *      }
+     *  }
+     * </pre>
+     * <p>
+     * This is an alternative to the more conservative approach of wrapping the
+     * checked exception in a RuntimeException:
+     * </p>
+     * <pre>
+     *  public int wrapExample { // note that there is no throws clause
+     *      try {
+     *          return invocation(); // throws IOException
+     *      } catch (Error e) {
+     *          throw e;
+     *      } catch (RuntimeException e) {
+     *          throw e;  // wraps a checked exception
+     *      } catch (Exception e) {
+     *          throw new UndeclaredThrowableException(e);  // wraps a checked 
exception
+     *      }
+     *  }
+     * </pre>
+     * <p>
+     * One downside to using this approach is that the java compiler will not
+     * allow invoking code to specify a checked exception in a catch clause
+     * unless there is some code path within the try block that has invoked a
+     * method declared with that checked exception. If the invoking site wishes
+     * to catch the shaded checked exception, it must either invoke the shaded
+     * code through a method re-declaring the desired checked exception, or
+     * catch Exception and use the instanceof operator. Either of these
+     * techniques are required when interacting with non-java jvm code such as
+     * Jython, Scala, or Groovy, since these languages do not consider any
+     * exceptions as checked.
+     * </p>
+     *
+     * @param throwable
+     *            The throwable to rethrow.
+     * @param <T> The type of the returned value.
+     * @return Never actually returned, this generic type matches any type
+     *         which the calling site requires. "Returning" the results of this
+     *         method, as done in the propagateExample above, will satisfy the
+     *         java compiler requirement that all code paths return a value.
+     * @since 3.14.0
+     * @see #wrapAndThrow(Throwable)
+     */
+    public static <T extends RuntimeException> T asRuntimeException(final 
Throwable throwable) {
+        // claim that the typeErasure invocation throws a RuntimeException
+        return ExceptionUtils.<T, RuntimeException>eraseType(throwable);
+    }
+
     /**
      * Claims a Throwable is another Throwable type using type erasure. This
      * hides a checked exception from the Java compiler, allowing a checked
@@ -751,7 +814,7 @@ public class ExceptionUtils {
     }
 
     /**
-     * Throws a checked exception without adding the exception to the throws
+     * Use to throw a checked exception without adding the exception to the 
throws
      * clause of the calling method. This method prevents throws clause
      * pollution and reduces the clutter of "Caused by" exceptions in the
      * stack trace.
@@ -800,17 +863,19 @@ public class ExceptionUtils {
      *
      * @param throwable
      *            The throwable to rethrow.
-     * @param <R> The type of the returned value.
+     * @param <T> The type of the returned value.
      * @return Never actually returned, this generic type matches any type
      *         which the calling site requires. "Returning" the results of this
      *         method, as done in the propagateExample above, will satisfy the
      *         java compiler requirement that all code paths return a value.
      * @since 3.5
      * @see #wrapAndThrow(Throwable)
+     * @deprecated Use {@link #asRuntimeException(Throwable)}.
      */
-    public static <R> R rethrow(final Throwable throwable) {
+    @Deprecated
+    public static <T> T rethrow(final Throwable throwable) {
         // claim that the typeErasure invocation throws a RuntimeException
-        return ExceptionUtils.<R, RuntimeException>eraseType(throwable);
+        return ExceptionUtils.<T, RuntimeException>eraseType(throwable);
     }
 
     /**
@@ -993,11 +1058,8 @@ public class ExceptionUtils {
      * @since 3.14.0
      */
     public static <T extends Throwable> T throwUnchecked(final T throwable) {
-        if (throwable instanceof RuntimeException) {
-            throw (RuntimeException) throwable;
-        }
-        if (throwable instanceof Error) {
-            throw (Error) throwable;
+        if (isUnchecked(throwable)) {
+            throw asRuntimeException(throwable);
         }
         return throwable;
     }
@@ -1021,7 +1083,7 @@ public class ExceptionUtils {
      *         method will satisfy the java compiler requirement that all code
      *         paths return a value.
      * @since 3.5
-     * @see #rethrow(Throwable)
+     * @see #asRuntimeException(Throwable)
      * @see #hasCause(Throwable, Class)
      */
     public static <R> R wrapAndThrow(final Throwable throwable) {
diff --git a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java 
b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
index bcb112ce8..eafc6535a 100644
--- a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
+++ b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
@@ -585,7 +585,7 @@ public class FastDatePrinter implements DatePrinter, 
Serializable {
                 rule.appendTo(buf, calendar);
             }
         } catch (final IOException ioe) {
-            ExceptionUtils.rethrow(ioe);
+            ExceptionUtils.asRuntimeException(ioe);
         }
         return buf;
     }
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 4845df492..02273d566 100644
--- a/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/exception/ExceptionUtilsTest.java
@@ -119,7 +119,8 @@ public class ExceptionUtilsTest extends AbstractLangTest {
         try {
             throw new IOException();
         } catch (final Exception e) {
-            return ExceptionUtils.<Integer>rethrow(e);
+            ExceptionUtils.asRuntimeException(e);
+            return -1;
         }
     }
 
@@ -203,6 +204,13 @@ public class ExceptionUtilsTest extends AbstractLangTest {
         assertEquals("IllegalArgumentException: Base", 
ExceptionUtils.getRootCauseMessage(th));
     }
 
+    @Test
+    public void testAsRuntimeException() {
+        final Exception expected = new InterruptedException();
+        final Exception actual = assertThrows(Exception.class, () -> 
ExceptionUtils.asRuntimeException(expected));
+        assertSame(expected, actual);
+    }
+
     @Test
     public void testCatchTechniques() {
         IOException ioe = assertThrows(IOException.class, 
ExceptionUtilsTest::throwsCheckedException);
@@ -765,7 +773,7 @@ public class ExceptionUtilsTest extends AbstractLangTest {
     }
 
     @Test
-    public void testThrow() {
+    public void testRethrow() {
         final Exception expected = new InterruptedException();
         final Exception actual = assertThrows(Exception.class, () -> 
ExceptionUtils.rethrow(expected));
         assertSame(expected, actual);

Reply via email to