This commit is contained in:
Gary Gregory 2019-08-22 22:49:53 -04:00
commit 5f2bf30ede
4 changed files with 326 additions and 0 deletions

View File

@ -505,6 +505,9 @@
<contributor>
<name>Mark Dacek</name>
</contributor>
<contributor>
<name>Peter Verhas</name>
</contributor>
</contributors>
<!-- Lang should depend on very little -->

View File

@ -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">

View File

@ -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}.
@ -255,6 +389,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

View File

@ -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<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();
@ -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<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();
@ -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<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();
@ -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<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();
@ -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<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();