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;