You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by jo...@apache.org on 2019/08/22 20:09:29 UTC

[commons-lang] branch master updated: PR: LANG-1447

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 bc16e01  PR: LANG-1447
bc16e01 is described below

commit bc16e0109a30b819c50895e157830fe9b3f8e93f
Author: Jochen Wiedmann <jo...@gmail.com>
AuthorDate: Thu Aug 22 22:09:11 2019 +0200

    PR: LANG-1447
    
    Added Functions.as* methods.
---
 pom.xml                                            |   3 +
 src/changes/changes.xml                            |   1 +
 .../java/org/apache/commons/lang3/Functions.java   | 150 ++++++++++++++++++
 .../org/apache/commons/lang3/FunctionsTest.java    | 174 ++++++++++++++++++++-
 4 files changed, 327 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 0ae407d..e9727c6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -505,6 +505,9 @@
     <contributor>
       <name>Mark Dacek</name>
     </contributor>
+    <contributor>
+      <name>Peter Verhas</name>
+    </contributor>
   </contributors>
 
   <!-- Lang should depend on very little -->
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d22ea6b..4535fa9 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -60,6 +60,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="update" dev="ggregory">commons.japicmp.version 0.13.1 -> 0.14.1.</action>
     <action                   type="update" dev="ggregory">checkstyle.version 8.18 -> 8.23.</action>
     <action                   type="update" dev="ggregory">junit-jupiter 5.5.0 -> 5.5.1.</action>
+    <action issue="LANG-1477" type="add" dev="jochen">Added Functions.as*, and tests thereof, as suggested by Peter Verhas</action>
   </release>
 
   <release version="3.9" date="2019-04-09" description="New features and bug fixes. Requires Java 8, supports Java 9, 10, 11">
diff --git a/src/main/java/org/apache/commons/lang3/Functions.java b/src/main/java/org/apache/commons/lang3/Functions.java
index ec4db67..5c7d032 100644
--- a/src/main/java/org/apache/commons/lang3/Functions.java
+++ b/src/main/java/org/apache/commons/lang3/Functions.java
@@ -19,6 +19,14 @@ package org.apache.commons.lang3;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.lang.reflect.UndeclaredThrowableException;
+import java.util.concurrent.Callable;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
 
 
 /** This class provides utility functions, and classes for working with the
@@ -124,6 +132,132 @@ public class Functions {
          */
         boolean test(O1 pObject1, O2 pObject2) throws T;
     }
+    @FunctionalInterface
+    public interface FailableSupplier<O, T extends Throwable> {
+        /**
+         * Supplies an object
+         * @return the suppliers result
+         * @throws T if the supplier fails
+         */
+        O get() throws T;
+    }
+
+    /**
+     * Converts the given {@link FailableRunnable} into a standard {@link Runnable}.
+     */
+    public static Runnable asRunnable(FailableRunnable<?> pRunnable) {
+    	return () -> {
+    		try {
+    			pRunnable.run();
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableConsumer} into a standard {@link Consumer}.
+     */
+    public static <I> Consumer<I> asConsumer(FailableConsumer<I,?> pConsumer) {
+    	return (pInput) -> {
+    		try {
+    			pConsumer.accept(pInput);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableCallable} into a standard {@link Callable}.
+     */
+    public static <O> Callable<O> asCallable(FailableCallable<O,?> pCallable) {
+    	return () -> {
+    		try {
+    			return pCallable.call();
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableBiConsumer} into a standard {@link BiConsumer}.
+     */
+    public static <I1,I2> BiConsumer<I1,I2> asBiConsumer(FailableBiConsumer<I1,I2,?> pConsumer) {
+    	return (pInput1, pInput2) -> {
+    		try {
+    			pConsumer.accept(pInput1, pInput2);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableFunction} into a standard {@link Function}.
+     */
+    public static <I,O> Function<I,O> asFunction(FailableFunction<I,O,?> pFunction) {
+    	return (pInput) -> {
+    		try {
+    			return pFunction.apply(pInput);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableBiFunction} into a standard {@link BiFunction}.
+     */
+    public static <I1,I2,O> BiFunction<I1,I2,O> asBiFunction(FailableBiFunction<I1,I2,O,?> pFunction) {
+    	return (pInput1, pInput2) -> {
+    		try {
+    			return pFunction.apply(pInput1, pInput2);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailablePredicate} into a standard {@link Predicate}.
+     */
+    public static <I> Predicate<I> asPredicate(FailablePredicate<I,?> pPredicate) {
+    	return (pInput) -> {
+    		try {
+    			return pPredicate.test(pInput);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableBiPredicate} into a standard {@link BiPredicate}.
+     */
+    public static <I1,I2> BiPredicate<I1,I2> asBiPredicate(FailableBiPredicate<I1,I2,?> pPredicate) {
+    	return (pInput1, pInput2) -> {
+    		try {
+    			return pPredicate.test(pInput1, pInput2);
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
+
+    /**
+     * Converts the given {@link FailableSupplier} into a standard {@link Supplier}.
+     */
+    public static <O> Supplier<O> asSupplier(FailableSupplier<O,?> pSupplier) {
+    	return () -> {
+    		try {
+    			return pSupplier.get();
+    		} catch (Throwable t) {
+    			throw rethrow(t);
+    		}
+    	};
+    }
 
     /**
      * Runs a runnable and rethrows any exception as a {@link RuntimeException}.
@@ -256,6 +390,22 @@ public class Functions {
     }
 
     /**
+     * Invokes the supplier, and returns the result.
+     * @param pSupplier The supplier to invoke.
+     * @param <O> The suppliers output type.
+     * @param <T> The type of checked exception, which the supplier can throw.
+     * @return The object, which has been created by the supplier
+     */
+    public static <O,T extends Throwable> O get(FailableSupplier<O,T> pSupplier) {
+    	try {
+    		return pSupplier.get();
+    	} 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>
diff --git a/src/test/java/org/apache/commons/lang3/FunctionsTest.java b/src/test/java/org/apache/commons/lang3/FunctionsTest.java
index 0808b80..d70c675 100644
--- a/src/test/java/org/apache/commons/lang3/FunctionsTest.java
+++ b/src/test/java/org/apache/commons/lang3/FunctionsTest.java
@@ -19,8 +19,19 @@ package org.apache.commons.lang3;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.lang.reflect.UndeclaredThrowableException;
-
+import java.util.concurrent.Callable;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.Functions.FailableBiConsumer;
+import org.apache.commons.lang3.Functions.FailableBiFunction;
+import org.apache.commons.lang3.Functions.FailableCallable;
 import org.apache.commons.lang3.Functions.FailableConsumer;
+import org.apache.commons.lang3.Functions.FailableFunction;
+import org.apache.commons.lang3.Functions.FailableSupplier;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -28,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 class FunctionsTest {
     public static class SomeException extends Exception {
@@ -128,6 +140,20 @@ class FunctionsTest {
     }
 
     @Test
+    void testAsRunnable() {
+        FailureOnOddInvocations.invocation = 0;
+        Runnable runnable = Functions.asRunnable(() -> new FailureOnOddInvocations());
+        UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () ->  runnable.run());
+        final Throwable cause = e.getCause();
+        assertNotNull(cause);
+        assertTrue(cause instanceof SomeException);
+        assertEquals("Odd Invocation: 1", cause.getMessage());
+
+        // Even invocation, should not throw an exception
+        runnable.run();
+    }
+
+    @Test
     void testCallable() {
         FailureOnOddInvocations.invocation = 0;
         UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () ->  Functions.run(FailureOnOddInvocations::new));
@@ -140,6 +166,25 @@ class FunctionsTest {
     }
 
     @Test
+    void testAsCallable() {
+        FailureOnOddInvocations.invocation = 0;
+        final FailableCallable<FailureOnOddInvocations,SomeException> failableCallable = () -> { return new FailureOnOddInvocations(); };
+        final Callable<FailureOnOddInvocations> callable = Functions.asCallable(failableCallable);
+        UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () ->  callable.call());
+        final Throwable cause = e.getCause();
+        assertNotNull(cause);
+        assertTrue(cause instanceof SomeException);
+        assertEquals("Odd Invocation: 1", cause.getMessage());
+        final FailureOnOddInvocations instance;
+        try {
+        	instance = callable.call();
+        } catch (Exception ex) {
+        	throw Functions.rethrow(ex);
+        }
+        assertNotNull(instance);
+    }
+
+    @Test
     void testAcceptConsumer() {
         final IllegalStateException ise = new IllegalStateException();
         final Testable testable = new Testable(ise);
@@ -163,6 +208,30 @@ class FunctionsTest {
     }
 
     @Test
+    void testAsConsumer() {
+        final IllegalStateException ise = new IllegalStateException();
+        final Testable testable = new Testable(ise);
+        final Consumer<Testable> consumer = Functions.asConsumer((t) -> t.test()); 
+        Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable));
+        assertSame(ise, e);
+
+        final Error error = new OutOfMemoryError();
+        testable.setThrowable(error);
+        e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable));
+        assertSame(error, e);
+
+        final IOException ioe = new IOException("Unknown I/O error");
+        testable.setThrowable(ioe);
+        e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable));
+        final Throwable t = e.getCause();
+        assertNotNull(t);
+        assertSame(ioe, t);
+
+        testable.setThrowable(null);
+        Functions.accept(Testable::test, testable);
+    }
+
+    @Test
     void testAcceptBiConsumer() {
         final IllegalStateException ise = new IllegalStateException();
         final Testable testable = new Testable(null);
@@ -185,6 +254,29 @@ class FunctionsTest {
     }
 
     @Test
+    void testAsBiConsumer() {
+        final IllegalStateException ise = new IllegalStateException();
+        final Testable testable = new Testable(null);
+        final FailableBiConsumer<Testable, Throwable, Throwable> failableBiConsumer = (t, th) -> { t.setThrowable(th); t.test(); }; 
+        final BiConsumer<Testable, Throwable> consumer = Functions.asBiConsumer(failableBiConsumer);
+        Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable, ise));
+        assertSame(ise, e);
+
+        final Error error = new OutOfMemoryError();
+        e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable, error));
+        assertSame(error, e);
+
+        final IOException ioe = new IOException("Unknown I/O error");
+        testable.setThrowable(ioe);
+        e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable,  ioe));
+        final Throwable t = e.getCause();
+        assertNotNull(t);
+        assertSame(ioe, t);
+
+        consumer.accept(testable, null);
+    }
+
+    @Test
     public void testApplyFunction() {
         final IllegalStateException ise = new IllegalStateException();
         final Testable testable = new Testable(ise);
@@ -210,6 +302,33 @@ class FunctionsTest {
     }
 
     @Test
+    public void testAsFunction() {
+        final IllegalStateException ise = new IllegalStateException();
+        final Testable testable = new Testable(ise);
+        final FailableFunction<Throwable,Integer,Throwable> failableFunction = (th) -> {
+        	testable.setThrowable(th);
+        	return Integer.valueOf(testable.testInt());
+        };
+        final Function<Throwable,Integer> function = Functions.asFunction(failableFunction);
+        Throwable e = assertThrows(IllegalStateException.class, () -> function.apply(ise));
+        assertSame(ise, e);
+
+        final Error error = new OutOfMemoryError();
+        testable.setThrowable(error);
+        e = assertThrows(OutOfMemoryError.class, () -> function.apply(error));
+        assertSame(error, e);
+
+        final IOException ioe = new IOException("Unknown I/O error");
+        testable.setThrowable(ioe);
+        e = assertThrows(UncheckedIOException.class, () -> function.apply(ioe));
+        final Throwable t = e.getCause();
+        assertNotNull(t);
+        assertSame(ioe, t);
+
+        assertEquals(0, function.apply(null).intValue());
+    }
+
+    @Test
     public void testApplyBiFunction() {
         final IllegalStateException ise = new IllegalStateException();
         final Testable testable = new Testable(null);
@@ -232,6 +351,59 @@ class FunctionsTest {
     }
 
     @Test
+    public void testAsBiFunction() {
+        final IllegalStateException ise = new IllegalStateException();
+        final Testable testable = new Testable(ise);
+        final FailableBiFunction<Testable,Throwable,Integer,Throwable> failableBiFunction = (t, th) -> {
+        	t.setThrowable(th);
+        	return Integer.valueOf(t.testInt());
+        };
+        final BiFunction<Testable,Throwable,Integer> biFunction = Functions.asBiFunction(failableBiFunction);
+        Throwable e = assertThrows(IllegalStateException.class, () -> biFunction.apply(testable, ise));
+        assertSame(ise, e);
+
+        final Error error = new OutOfMemoryError();
+        testable.setThrowable(error);
+        e = assertThrows(OutOfMemoryError.class, () -> biFunction.apply(testable, error));
+        assertSame(error, e);
+
+        final IOException ioe = new IOException("Unknown I/O error");
+        testable.setThrowable(ioe);
+        e = assertThrows(UncheckedIOException.class, () -> biFunction.apply(testable, ioe));
+        final Throwable t = e.getCause();
+        assertNotNull(t);
+        assertSame(ioe, t);
+
+        assertEquals(0, biFunction.apply(testable, null).intValue());
+    }
+
+    @Test
+    public void testGetFromSupplier() {
+        FailureOnOddInvocations.invocation = 0;
+        UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () ->  Functions.run(FailureOnOddInvocations::new));
+        final Throwable cause = e.getCause();
+        assertNotNull(cause);
+        assertTrue(cause instanceof SomeException);
+        assertEquals("Odd Invocation: 1", cause.getMessage());
+        final FailureOnOddInvocations instance = Functions.call(FailureOnOddInvocations::new);
+        assertNotNull(instance);
+    }
+
+    @Test
+    public void testAsSupplier() {
+        FailureOnOddInvocations.invocation = 0;
+        final FailableSupplier<FailureOnOddInvocations,Throwable> failableSupplier = () -> { return new FailureOnOddInvocations(); };
+        final Supplier<FailureOnOddInvocations> supplier = Functions.asSupplier(failableSupplier);
+        UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () ->  supplier.get());
+        final Throwable cause = e.getCause();
+        assertNotNull(cause);
+        assertTrue(cause instanceof SomeException);
+        assertEquals("Odd Invocation: 1", cause.getMessage());
+        final FailureOnOddInvocations instance = supplier.get();
+        assertNotNull(instance);
+    }
+
+    @Test
     public void testTryWithResources() {
         final CloseableObject co = new CloseableObject();
         final FailableConsumer<Throwable, ? extends Throwable> consumer = co::run;