This change is not null-safe for isUnchecked. This case is missing
from the tests (and currently fails):

    @Test
    public void testIsUnchecked_null() {
        assertFalse(ExceptionUtils.isUnchecked(null));
    }

The case fails because it simply negates isChecked. Both methods
should return false when passed a null. Since instanceof handles null
then the isUnchecked method can be updated to:

    public static boolean isUnchecked(final Throwable throwable) {
        return (throwable instanceof Error) || (throwable instanceof
RuntimeException);
    }

This implementation passes all current tests plus the extra one above.

On Sun, 2 Jul 2023 at 20:55, <ggreg...@apache.org> wrote:
>
> 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 98ef0a413 [LANG-1647] Add and ExceptionUtils.isChecked() and 
> isUnchecked() #1069
> 98ef0a413 is described below
>
> commit 98ef0a4138ac032923c4fb12a97b388bde354668
> Author: Gary Gregory <garydgreg...@gmail.com>
> AuthorDate: Sun Jul 2 15:55:12 2023 -0400
>
>     [LANG-1647] Add and ExceptionUtils.isChecked() and isUnchecked() #1069
> ---
>  src/changes/changes.xml                            |   2 +
>  .../java/org/apache/commons/lang3/Functions.java   |   8 +-
>  .../commons/lang3/concurrent/ConcurrentUtils.java  |  21 +---
>  .../apache/commons/lang3/concurrent/Memoizer.java  |  10 +-
>  .../commons/lang3/exception/ExceptionUtils.java    | 119 
> ++++++++++++---------
>  .../apache/commons/lang3/function/Failable.java    |   8 +-
>  6 files changed, 77 insertions(+), 91 deletions(-)
>
> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> index 98a831c53..d4e0e4210 100644
> --- a/src/changes/changes.xml
> +++ b/src/changes/changes.xml
> @@ -208,6 +208,8 @@ The <action> type attribute can be add,update,fix,remove.
>      <action                   type="add" dev="ggregory" due-to="Gary 
> Gregory">Add Pair.accept(FailableBiConsumer).</action>
>      <action                   type="add" dev="ggregory" due-to="Gary 
> Gregory">Add Pair.apply(FailableBiFunction).</action>
>      <action issue="LANG-1677" type="add" dev="ggregory" due-to="Dennis 
> Baerten, Gary Gregory">Add ReflectionDiffBuilder.setExcludeFieldNames(...) 
> and DiffExclude a… #838.</action>
> +    <action issue="LANG-1647" type="add" dev="ggregory" due-to="Arturo 
> Bernal, Dimitrios Efthymiou, Gary Gregory">Add and ExceptionUtils.isChecked() 
> and isUnchecked() #1069</action>
> +    <action                   type="add" dev="ggregory" due-to="Gary 
> Gregory">Add and use ExceptionUtils.throwUnchecked(throwable).</action>
>      <!-- UPDATE -->
>      <action                   type="update" dev="ggregory" 
> due-to="Dependabot, XenoAmess, Gary Gregory">Bump actions/cache from 2.1.4 to 
> 3.0.10 #742, #752, #764, #833, #867, #959, #964.</action>
>      <action                   type="update" dev="ggregory" 
> due-to="Dependabot, Gary Gregory">Bump actions/checkout from 2 to 3.1.0 #819, 
> #825, #859, #963.</action>
> diff --git a/src/main/java/org/apache/commons/lang3/Functions.java 
> b/src/main/java/org/apache/commons/lang3/Functions.java
> index e5e4e106c..7e0de8ba4 100644
> --- a/src/main/java/org/apache/commons/lang3/Functions.java
> +++ b/src/main/java/org/apache/commons/lang3/Functions.java
> @@ -33,6 +33,7 @@ import java.util.function.Supplier;
>  import java.util.stream.Stream;
>
>  import org.apache.commons.lang3.Streams.FailableStream;
> +import org.apache.commons.lang3.exception.ExceptionUtils;
>  import org.apache.commons.lang3.function.Failable;
>  import org.apache.commons.lang3.function.FailableBooleanSupplier;
>
> @@ -521,12 +522,7 @@ public class Functions {
>       */
>      public static RuntimeException rethrow(final Throwable throwable) {
>          Objects.requireNonNull(throwable, "throwable");
> -        if (throwable instanceof RuntimeException) {
> -            throw (RuntimeException) throwable;
> -        }
> -        if (throwable instanceof Error) {
> -            throw (Error) throwable;
> -        }
> +        ExceptionUtils.throwUnchecked(throwable);
>          if (throwable instanceof IOException) {
>              throw new UncheckedIOException((IOException) throwable);
>          }
> diff --git 
> a/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java 
> b/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
> index bafbad67d..42b6343da 100644
> --- a/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
> +++ b/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
> @@ -61,8 +61,7 @@ public class ConcurrentUtils {
>          if (ex == null || ex.getCause() == null) {
>              return null;
>          }
> -
> -        throwCause(ex);
> +        ExceptionUtils.throwUnchecked(ex.getCause());
>          return new ConcurrentException(ex.getMessage(), ex.getCause());
>      }
>
> @@ -84,7 +83,7 @@ public class ConcurrentUtils {
>              return null;
>          }
>
> -        throwCause(ex);
> +        ExceptionUtils.throwUnchecked(ex.getCause());
>          return new ConcurrentRuntimeException(ex.getMessage(), 
> ex.getCause());
>      }
>
> @@ -145,22 +144,6 @@ public class ConcurrentUtils {
>          return ex;
>      }
>
> -    /**
> -     * Tests whether the cause of the specified {@link ExecutionException}
> -     * should be thrown and does it if necessary.
> -     *
> -     * @param ex the exception in question
> -     */
> -    private static void throwCause(final ExecutionException ex) {
> -        if (ex.getCause() instanceof RuntimeException) {
> -            throw (RuntimeException) ex.getCause();
> -        }
> -
> -        if (ex.getCause() instanceof Error) {
> -            throw (Error) ex.getCause();
> -        }
> -    }
> -
>      /**
>       * Invokes the specified {@link ConcurrentInitializer} and returns the
>       * object produced by the initializer. This method just invokes the 
> {@code
> diff --git a/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java 
> b/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
> index dd0e3ef22..51b05526f 100644
> --- a/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
> +++ b/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
> @@ -23,6 +23,8 @@ import java.util.concurrent.ExecutionException;
>  import java.util.concurrent.Future;
>  import java.util.function.Function;
>
> +import org.apache.commons.lang3.exception.ExceptionUtils;
> +
>  /**
>   * Definition of an interface for a wrapper around a calculation that takes 
> a single parameter and returns a result. The
>   * results for the calculation will be cached for future requests.
> @@ -143,12 +145,6 @@ public class Memoizer<I, O> implements Computable<I, O> {
>       * @return a RuntimeException, Error or an IllegalStateException
>       */
>      private RuntimeException launderException(final Throwable throwable) {
> -        if (throwable instanceof RuntimeException) {
> -            return (RuntimeException) throwable;
> -        }
> -        if (throwable instanceof Error) {
> -            throw (Error) throwable;
> -        }
> -        throw new IllegalStateException("Unchecked exception", throwable);
> +        throw new IllegalStateException("Unchecked exception", 
> ExceptionUtils.throwUnchecked(throwable));
>      }
>  }
> 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 6f320a27d..3125aab41 100644
> --- a/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> +++ b/src/main/java/org/apache/commons/lang3/exception/ExceptionUtils.java
> @@ -42,8 +42,6 @@ import org.apache.commons.lang3.StringUtils;
>   */
>  public class ExceptionUtils {
>
> -    private static final int NOT_FOUND = -1;
> -
>      /**
>       * The names of methods commonly used to access a wrapped exception.
>       */
> @@ -63,6 +61,8 @@ public class ExceptionUtils {
>          "getThrowable",
>      };
>
> +    private static final int NOT_FOUND = -1;
> +
>      /**
>       * Used when printing stack frames to denote the start of a
>       * wrapped exception.
> @@ -82,6 +82,26 @@ public class ExceptionUtils {
>          throw (T) throwable;
>      }
>
> +    /**
> +     * 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);
> +    }
> +
>      /**
>       * Introspects the {@link Throwable} to obtain the cause.
>       *
> @@ -434,26 +454,6 @@ 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 {@link Throwable} objects in the
>       * exception chain.
> @@ -620,6 +620,30 @@ public class ExceptionUtils {
>          return indexOf(throwable, type, fromIndex, true);
>      }
>
> +    /**
> +     * Checks if a throwable represents a checked exception
> +     *
> +     * @param throwable
> +     *            The throwable to check.
> +     * @return True if the given Throwable is a checked exception.
> +     * @since 3.13.0
> +     */
> +    public static boolean isChecked(final Throwable throwable) {
> +        return throwable != null && !(throwable instanceof Error) && 
> !(throwable instanceof RuntimeException);
> +    }
> +
> +    /**
> +     * Checks if a throwable represents an unchecked exception
> +     *
> +     * @param throwable
> +     *            The throwable to check.
> +     * @return True if the given Throwable is an unchecked exception.
> +     * @since 3.13.0
> +     */
> +    public static boolean isUnchecked(final Throwable throwable) {
> +        return !isChecked(throwable);
> +    }
> +
>      /**
>       * Prints a compact stack trace for the root cause of a throwable
>       * to {@code System.err}.
> @@ -940,6 +964,25 @@ public class ExceptionUtils {
>          return throwableOf(throwable, type, fromIndex, true);
>      }
>
> +    /**
> +     * Tests whether the cause of the specified {@link Throwable}
> +     * should be thrown and does it if necessary.
> +     *
> +     * @param <T> The Throwable type.
> +     * @param throwable the throwable to test and throw or return.
> +     * @return the given throwable.
> +     * @since 3.13.0
> +     */
> +    public static <T> T throwUnchecked(final T throwable) {
> +        if (throwable instanceof RuntimeException) {
> +            throw (RuntimeException) throwable;
> +        }
> +        if (throwable instanceof Error) {
> +            throw (Error) throwable;
> +        }
> +        return throwable;
> +    }
> +
>      /**
>       * Throws a checked exception without adding the exception to the throws
>       * clause of the calling method. For checked exceptions, this method 
> throws
> @@ -963,37 +1006,7 @@ public class ExceptionUtils {
>       * @see #hasCause(Throwable, Class)
>       */
>      public static <R> R wrapAndThrow(final Throwable throwable) {
> -        if (throwable instanceof RuntimeException) {
> -            throw (RuntimeException) throwable;
> -        }
> -        if (throwable instanceof Error) {
> -            throw (Error) throwable;
> -        }
> -        throw new UndeclaredThrowableException(throwable);
> -    }
> -
> -    /**
> -     * Checks if a throwable represents a checked exception
> -     *
> -     * @param throwable
> -     *            The throwable to check.
> -     * @return True if the given Throwable is a checked exception.
> -     * @since 3.13.0
> -     */
> -    public static boolean isChecked(final Throwable throwable) {
> -        return throwable != null && !(throwable instanceof Error) && 
> !(throwable instanceof RuntimeException);
> -    }
> -
> -    /**
> -     * Checks if a throwable represents an unchecked exception
> -     *
> -     * @param throwable
> -     *            The throwable to check.
> -     * @return True if the given Throwable is an unchecked exception.
> -     * @since 3.13.0
> -     */
> -    public static boolean isUnchecked(final Throwable throwable) {
> -        return !isChecked(throwable);
> +        throw new UndeclaredThrowableException(throwUnchecked(throwable));
>      }
>
>      /**
> diff --git a/src/main/java/org/apache/commons/lang3/function/Failable.java 
> b/src/main/java/org/apache/commons/lang3/function/Failable.java
> index 1d1e8f147..e127a83f4 100644
> --- a/src/main/java/org/apache/commons/lang3/function/Failable.java
> +++ b/src/main/java/org/apache/commons/lang3/function/Failable.java
> @@ -32,6 +32,7 @@ import java.util.function.Predicate;
>  import java.util.function.Supplier;
>  import java.util.stream.Stream;
>
> +import org.apache.commons.lang3.exception.ExceptionUtils;
>  import org.apache.commons.lang3.stream.Streams;
>  import org.apache.commons.lang3.stream.Streams.FailableStream;
>
> @@ -407,12 +408,7 @@ public class Failable {
>       */
>      public static RuntimeException rethrow(final Throwable throwable) {
>          Objects.requireNonNull(throwable, "throwable");
> -        if (throwable instanceof RuntimeException) {
> -            throw (RuntimeException) throwable;
> -        }
> -        if (throwable instanceof Error) {
> -            throw (Error) throwable;
> -        }
> +        ExceptionUtils.throwUnchecked(throwable);
>          if (throwable instanceof IOException) {
>              throw new UncheckedIOException((IOException) throwable);
>          }
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to