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, <[email protected]> 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 <[email protected]>
> 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: [email protected]
For additional commands, e-mail: [email protected]