diff --git a/pom.xml b/pom.xml
index 0ae407d7f..e9727c6e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -505,6 +505,9 @@
Mark Dacek
+
+ Peter Verhas
+
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d22ea6b01..4535fa979 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -60,6 +60,7 @@ The type attribute can be add,update,fix,remove.
commons.japicmp.version 0.13.1 -> 0.14.1.
checkstyle.version 8.18 -> 8.23.
junit-jupiter 5.5.0 -> 5.5.1.
+ Added Functions.as*, and tests thereof, as suggested by Peter Verhas
diff --git a/src/main/java/org/apache/commons/lang3/Functions.java b/src/main/java/org/apache/commons/lang3/Functions.java
index ec4db67ae..5c7d03254 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 {
+ /**
+ * 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 Consumer asConsumer(FailableConsumer 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 Callable asCallable(FailableCallable pCallable) {
+ return () -> {
+ try {
+ return pCallable.call();
+ } catch (Throwable t) {
+ throw rethrow(t);
+ }
+ };
+ }
+
+ /**
+ * Converts the given {@link FailableBiConsumer} into a standard {@link BiConsumer}.
+ */
+ public static BiConsumer asBiConsumer(FailableBiConsumer 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 Function asFunction(FailableFunction 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 BiFunction asBiFunction(FailableBiFunction 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 Predicate asPredicate(FailablePredicate 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 BiPredicate asBiPredicate(FailableBiPredicate 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 Supplier asSupplier(FailableSupplier pSupplier) {
+ return () -> {
+ try {
+ return pSupplier.get();
+ } catch (Throwable t) {
+ throw rethrow(t);
+ }
+ };
+ }
/**
* Runs a runnable and rethrows any exception as a {@link RuntimeException}.
@@ -255,6 +389,22 @@ public class Functions {
}
}
+ /**
+ * Invokes the supplier, and returns the result.
+ * @param pSupplier The supplier to invoke.
+ * @param The suppliers output type.
+ * @param The type of checked exception, which the supplier can throw.
+ * @return The object, which has been created by the supplier
+ */
+ public static O get(FailableSupplier 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
diff --git a/src/test/java/org/apache/commons/lang3/FunctionsTest.java b/src/test/java/org/apache/commons/lang3/FunctionsTest.java
index 0808b8069..d70c675bf 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 {
@@ -127,6 +139,20 @@ class FunctionsTest {
Functions.run(FailureOnOddInvocations::new);
}
+ @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;
@@ -139,6 +165,25 @@ class FunctionsTest {
assertNotNull(instance);
}
+ @Test
+ void testAsCallable() {
+ FailureOnOddInvocations.invocation = 0;
+ final FailableCallable failableCallable = () -> { return new FailureOnOddInvocations(); };
+ final Callable 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();
@@ -162,6 +207,30 @@ class FunctionsTest {
Functions.accept(Testable::test, testable);
}
+ @Test
+ void testAsConsumer() {
+ final IllegalStateException ise = new IllegalStateException();
+ final Testable testable = new Testable(ise);
+ final Consumer 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();
@@ -184,6 +253,29 @@ class FunctionsTest {
Functions.accept(Testable::test, testable, (Throwable) null);
}
+ @Test
+ void testAsBiConsumer() {
+ final IllegalStateException ise = new IllegalStateException();
+ final Testable testable = new Testable(null);
+ final FailableBiConsumer failableBiConsumer = (t, th) -> { t.setThrowable(th); t.test(); };
+ final BiConsumer 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();
@@ -209,6 +301,33 @@ class FunctionsTest {
assertEquals(0, i.intValue());
}
+ @Test
+ public void testAsFunction() {
+ final IllegalStateException ise = new IllegalStateException();
+ final Testable testable = new Testable(ise);
+ final FailableFunction failableFunction = (th) -> {
+ testable.setThrowable(th);
+ return Integer.valueOf(testable.testInt());
+ };
+ final Function 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();
@@ -231,6 +350,59 @@ class FunctionsTest {
assertEquals(0, i.intValue());
}
+ @Test
+ public void testAsBiFunction() {
+ final IllegalStateException ise = new IllegalStateException();
+ final Testable testable = new Testable(ise);
+ final FailableBiFunction failableBiFunction = (t, th) -> {
+ t.setThrowable(th);
+ return Integer.valueOf(t.testInt());
+ };
+ final BiFunction 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 failableSupplier = () -> { return new FailureOnOddInvocations(); };
+ final Supplier 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();