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