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) <jochen.wiedm...@softwareag.com>
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());
+       }
 }

Reply via email to