This is an automated email from the ASF dual-hosted git repository.
jochen 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 2ebc17b Added Functions.tryWithResources.
2ebc17b is described below
commit 2ebc17ba3f244ae44aae46273aeef7e321f9542a
Author: Jochen Wiedmann (jwi) <[email protected]>
AuthorDate: Tue Jan 29 11:42:07 2019 +0100
Added Functions.tryWithResources.
---
.../java/org/apache/commons/lang3/Functions.java | 121 +++++++++++++++++++--
.../org/apache/commons/lang3/FunctionsTest.java | 60 ++++++++++
2 files changed, 174 insertions(+), 7 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/Functions.java
b/src/main/java/org/apache/commons/lang3/Functions.java
index 9b6168f..5eaed0c 100644
--- a/src/main/java/org/apache/commons/lang3/Functions.java
+++ b/src/main/java/org/apache/commons/lang3/Functions.java
@@ -18,11 +18,8 @@ package org.apache.commons.lang3;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
-import java.util.ArrayList;
-import org.apache.commons.lang3.exception.ExceptionUtils;
/** This class provides utility functions, and classes for working with the
* {@code java.util.function} package, or more generally, with Java 8
@@ -73,6 +70,14 @@ public class Functions {
public interface FailableBiFunction<I1,I2,O,T extends Throwable> {
public O apply(I1 pInput1, I2 pInput2) throws T;
}
+ @FunctionalInterface
+ public interface FailablePredicate<O,T extends Throwable> {
+ public boolean test(O pObject) throws T;
+ }
+ @FunctionalInterface
+ public interface FailableBiPredicate<O1,O2,T extends Throwable> {
+ public boolean test(O1 pObject1, O2 pObject2) throws T;
+ }
public static <T extends Throwable> void run(FailableRunnable<T>
pRunnable) {
try {
@@ -122,6 +127,112 @@ public class Functions {
}
}
+ public static <O,T extends Throwable> boolean
test(FailablePredicate<O,T> pPredicate, O pObject) {
+ try {
+ return pPredicate.test(pObject);
+ } catch (Throwable t) {
+ throw rethrow(t);
+ }
+ }
+
+ public static <O1,O2,T extends Throwable> boolean
test(FailableBiPredicate<O1,O2,T> pPredicate, O1 pObject1, O2 pObject2) {
+ try {
+ return pPredicate.test(pObject1, pObject2);
+ } catch (Throwable t) {
+ throw rethrow(t);
+ }
+ }
+
+ /**
+ * A simple try-with-resources implementation, that can be used, if your
+ * objects do not implement the {@link AutoCloseable} interface. The
method
+ * executes the {@code pAction}. The method guarantees, that
<em>all</em>
+ * the {@code pResources} are being executed, in the given order,
afterwards,
+ * and regardless of success, or failure. If either the original
action, or
+ * any of the resource action fails, then the <em>first</em> failure
(aka
+ * {@link Throwable} is rethrown. Example use:
+ * <pre>
+ * final FileInputStream fis = new FileInputStream("my.file");
+ * Functions.tryWithResources(useInputStream(fis), null, () ->
fis.close());
+ * </pre>
+ * @param pAction The action to execute. This object <em>will</em>
always
+ * be invoked.
+ * @param pErrorHandler An optional error handler, which will be
invoked finally,
+ * if any error occurred. The error handler will receive the first
+ * error, aka {@link Throwable}.
+ * @param pResources The resource actions to execute. <em>All</em>
resource
+ * actions will be invoked, in the given order. A resource action is
an
+ * instance of {@link FailableRunnable}, which will be executed.
+ * @see #tryWithResources(FailableRunnable, FailableRunnable...)
+ */
+ @SafeVarargs
+ public static <O> void tryWithResources(FailableRunnable<? extends
Throwable> pAction,
+
FailableConsumer<Throwable,? extends Throwable> pErrorHandler,
+
FailableRunnable<? extends Throwable>... pResources) {
+ final FailableConsumer<Throwable,? extends Throwable>
errorHandler;
+ if (pErrorHandler == null) {
+ errorHandler = (t) -> rethrow(t);
+ } else {
+ errorHandler = pErrorHandler;
+ }
+ if (pResources != null) {
+ for (FailableRunnable<? extends Throwable> runnable :
pResources) {
+ if (runnable == null) {
+ throw new NullPointerException("A
resource action must not be null.");
+ }
+ }
+ }
+ Throwable th = null;
+ try {
+ pAction.run();
+ } catch (Throwable t) {
+ th = t;
+ }
+ if (pResources != null) {
+ for (FailableRunnable<? extends Object> runnable :
pResources) {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ if (th == null) {
+ th = t;
+ }
+ }
+ }
+ }
+ if (th != null) {
+ try {
+ errorHandler.accept(th);
+ } catch (Throwable t) {
+ throw rethrow(t);
+ }
+ }
+ }
+
+ /**
+ * A simple try-with-resources implementation, that can be used, if your
+ * objects do not implement the {@link AutoCloseable} interface. The
method
+ * executes the {@code pAction}. The method guarantees, that
<em>all</em>
+ * the {@code pResources} are being executed, in the given order,
afterwards,
+ * and regardless of success, or failure. If either the original
action, or
+ * any of the resource action fails, then the <em>first</em> failure
(aka
+ * {@link Throwable} is rethrown. Example use:
+ * <pre>
+ * final FileInputStream fis = new FileInputStream("my.file");
+ * Functions.tryWithResources(useInputStream(fis), () -> fis.close());
+ * </pre>
+ * @param pAction The action to execute. This object <em>will</em>
always
+ * be invoked.
+ * @param pResources The resource actions to execute. <em>All</em>
resource
+ * actions will be invoked, in the given order. A resource action is
an
+ * instance of {@link FailableRunnable}, which will be executed.
+ * @see #tryWithResources(FailableRunnable, FailableConsumer,
FailableRunnable...)
+ */
+ @SafeVarargs
+ public static <O> void tryWithResources(FailableRunnable<? extends
Throwable> pAction,
+
FailableRunnable<? extends Throwable>... pResources) {
+ tryWithResources(pAction, null, pResources);
+ }
+
public static RuntimeException rethrow(Throwable pThrowable) {
if (pThrowable == null) {
throw new NullPointerException("The Throwable must not
be null.");
@@ -137,8 +248,4 @@ public class Functions {
}
}
}
-
- public static void test() throws Exception {
- run(() -> ArrayList.class.newInstance());
- }
}
diff --git a/src/test/java/org/apache/commons/lang3/FunctionsTest.java
b/src/test/java/org/apache/commons/lang3/FunctionsTest.java
index 4f62c53..baef2dd 100644
--- a/src/test/java/org/apache/commons/lang3/FunctionsTest.java
+++ b/src/test/java/org/apache/commons/lang3/FunctionsTest.java
@@ -6,6 +6,8 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.UndeclaredThrowableException;
+import org.apache.commons.lang3.Functions.FailableBiConsumer;
+import org.apache.commons.lang3.Functions.FailableConsumer;
import org.junit.jupiter.api.Test;
class FunctionsTest {
@@ -71,6 +73,28 @@ class FunctionsTest {
}
}
+ public static class CloseableObject {
+ private boolean closed;
+
+ public void run(Throwable pTh) throws Throwable {
+ if (pTh != null) {
+ throw pTh;
+ }
+ }
+
+ public void reset() {
+ closed = false;
+ }
+
+ public void close() {
+ closed = true;
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+ }
+
@Test
void testRunnable() {
FailureOnOddInvocations.invocation = 0;
@@ -229,4 +253,40 @@ class FunctionsTest {
assertNotNull(i);
assertEquals(0, i.intValue());
}
+
+ @Test
+ public void testTryWithResources() {
+ final CloseableObject co = new CloseableObject();
+ final FailableConsumer<Throwable,? extends Throwable> consumer
= (th) -> co.run(th);
+ final IllegalStateException ise = new IllegalStateException();
+ try {
+ Functions.tryWithResources(() -> consumer.accept(ise),
() -> co.close());
+ fail("Expected Exception");
+ } catch (IllegalStateException e) {
+ assertSame(ise, e);
+ }
+ assertTrue(co.isClosed());
+ co.reset();
+ final Error error = new OutOfMemoryError();
+ try {
+ Functions.tryWithResources(() ->
consumer.accept(error), () -> co.close());
+ fail("Expected Exception");
+ } catch (OutOfMemoryError e) {
+ assertSame(error, e);
+ }
+ assertTrue(co.isClosed());
+ co.reset();
+ final IOException ioe = new IOException("Unknown I/O error");
+ try {
+ Functions.tryWithResources(() -> consumer.accept(ioe),
() -> co.close());
+ fail("Expected Exception");
+ } catch (UncheckedIOException e) {
+ final IOException cause = e.getCause();
+ assertSame(ioe, cause);
+ }
+ assertTrue(co.isClosed());
+ co.reset();
+ Functions.tryWithResources(() -> consumer.accept(null), () ->
co.close());
+ assertTrue(co.isClosed());
+ }
}