This is an automated email from the ASF dual-hosted git repository.

ggregory 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 f75f5b9  Add MethodInvokers.
f75f5b9 is described below

commit f75f5b9373c0c9b8c3257642468e10a792afb6a4
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Wed Nov 17 00:42:26 2021 -0500

    Add MethodInvokers.
---
 src/changes/changes.xml                            |   1 +
 .../commons/lang3/function/MethodInvokers.java     | 259 +++++++++++++++++++++
 .../lang3/exception/CustomCheckedException.java    |  38 +++
 .../lang3/exception/CustomUncheckedException.java  |  38 +++
 .../lang3/function/AnnotationTestFixture.java      |  29 +++
 .../commons/lang3/function/MethodFixtures.java     | 222 ++++++++++++++++++
 .../function/MethodInvokersBiConsumerTest.java     |  56 +++++
 .../function/MethodInvokersBiFunctionTest.java     |  65 ++++++
 .../MethodInvokersFailableBiConsumerTest.java      |  62 +++++
 .../MethodInvokersFailableBiFunctionTest.java      |  69 ++++++
 .../MethodInvokersFailableFunctionTest.java        |  84 +++++++
 .../MethodInvokersFailableSupplierTest.java        |  44 ++++
 .../lang3/function/MethodInvokersFunctionTest.java | 101 ++++++++
 .../lang3/function/MethodInvokersSupplierTest.java |  48 ++++
 14 files changed, 1116 insertions(+)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0c5e9c5..f938262 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -95,6 +95,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add UncheckedReflectiveOperationException.</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add and use ClassUtils.isPublic(Class).</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add UncheckedIllegalAccessException.</action>
+    <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add MethodInvokers.</action>
     <!-- UPDATE -->
     <action                   type="update" dev="ggregory" due-to="Dependabot, 
Gary Gregory">Bump spotbugs-maven-plugin from 4.2.0 to 4.4.2.2 #735, #808, 
#822.</action>
     <action                   type="update" dev="ggregory" due-to="Dependabot, 
XenoAmess">Bump Bump actions/cache from v2.1.4 to v2.1.6 #742, #752, 
#764.</action>
diff --git 
a/src/main/java/org/apache/commons/lang3/function/MethodInvokers.java 
b/src/main/java/org/apache/commons/lang3/function/MethodInvokers.java
new file mode 100644
index 0000000..39f3b1e
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/function/MethodInvokers.java
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleProxies;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.exception.UncheckedIllegalAccessException;
+
+/**
+ * Converts {@link Method} objects to lambdas.
+ * <p>
+ * More specifically, produces instances of single-method interfaces which 
redirect calls to methods; see
+ * {@link #asInterfaceInstance(Class, Method)}.
+ * </p>
+ * <h2>Calling supplier methods with no arguments</h2>
+ * <p>
+ * If the interface's single-method defines no arguments, use {@link 
#asFunction(Method)} and then apply the function
+ * passing in the object to receive the method call.
+ * </p>
+ * <p>
+ * For example to invoke {@link String#length()}:
+ * </p>
+ *
+ * <pre>
+ * final Method method = String.class.getMethod("length");
+ * final Function&lt;String, Integer&gt; function = 
MethodInvokers.asFunction(method);
+ * assertEquals(3, function.apply("ABC"));
+ * </pre>
+ *
+ * <h2>Calling function methods with one argument</h2>
+ * <p>
+ * If the interface's single-method defines one argument, use {@link 
#asBiFunction(Method)} and then apply the function
+ * passing in the object to receive the method call. The second argument to 
the function is the only argument to the
+ * method.
+ * </p>
+ * <p>
+ * For example to invoke {@link String#charAt(int)}:
+ * </p>
+ *
+ * <pre>
+ * final Method method = String.class.getMethod("charAt", int.class);
+ * final BiFunction&lt;String, Integer, Character&gt; function = 
MethodInvokers.asBiFunction(method);
+ * assertEquals('C', function.apply("ABC", 2));
+ * </pre>
+ *
+ * @since 3.13.0
+ */
+public final class MethodInvokers {
+
+    /**
+     * Produces a {@link BiConsumer} for a given <em>consumer</em> Method. For 
example, a classic setter method (as opposed
+     * to a fluent setter). You call the BiConsumer with two arguments: (1) 
the object receiving the method call, and (2)
+     * the method argument.
+     *
+     * @param <T> the type of the first argument to the operation: The type 
containing the Method.
+     * @param <U> the type of the second argument to the operation: The type 
of the method argument.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U> BiConsumer<T, U> asBiConsumer(final Method method) {
+        return asInterfaceInstance(BiConsumer.class, method);
+    }
+
+    /**
+     * Produces a {@link BiFunction} for a given a <em>function</em> Method. 
You call the BiFunction with two arguments: (1)
+     * the object receiving the method call, and (2) the method argument. The 
BiFunction return type must match the method's
+     * return type.
+     * <p>
+     * For example to invoke {@link String#charAt(int)}:
+     * </p>
+     *
+     * <pre>
+     * final Method method = String.class.getMethod("charAt", int.class);
+     * final BiFunction&lt;String, Integer, Character&gt; function = 
MethodInvokers.asBiFunction(method);
+     * assertEquals('C', function.apply("ABC", 2));
+     * </pre>
+     *
+     * @param <T> the type of the first argument to the function: The type 
containing the method.
+     * @param <U> the type of the second argument to the function: the method 
argument type.
+     * @param <R> the type of the result of the function: The method return 
type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U, R> BiFunction<T, U, R> asBiFunction(final Method 
method) {
+        return asInterfaceInstance(BiFunction.class, method);
+    }
+
+    /**
+     * Produces a {@link FailableBiConsumer} for a given <em>consumer</em> 
Method. For example, a classic setter method (as
+     * opposed to a fluent setter). You call the FailableBiConsumer with two 
arguments: (1) the object receiving the method
+     * call, and (2) the method argument.
+     *
+     * @param <T> the type of the first argument to the operation: The type 
containing the Method.
+     * @param <U> the type of the second argument to the operation: The type 
of the method argument.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U> FailableBiConsumer<T, U, Throwable> 
asFailableBiConsumer(final Method method) {
+        return asInterfaceInstance(FailableBiConsumer.class, method);
+    }
+
+    /**
+     * Produces a {@link FailableBiFunction} for a given a <em>function</em> 
Method. You call the FailableBiFunction with
+     * two arguments: (1) the object receiving the method call, and (2) the 
method argument. The BiFunction return type must
+     * match the method's return type.
+     *
+     * @param <T> the type of the first argument to the function: The type 
containing the method.
+     * @param <U> the type of the second argument to the function: the method 
argument type.
+     * @param <R> the type of the result of the function: The method return 
type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U, R> FailableBiFunction<T, U, R, Throwable> 
asFailableBiFunction(final Method method) {
+        return asInterfaceInstance(FailableBiFunction.class, method);
+    }
+
+    /**
+     * Produces a {@link FailableFunction} for a given a <em>supplier</em> 
Method. You call the Function with one argument:
+     * the object receiving the method call. The FailableFunction return type 
must match the method's return type.
+     *
+     * @param <T> the type of the first argument to the function: The type 
containing the method.
+     * @param <R> the type of the result of the function: The method return 
type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, R> FailableFunction<T, R, Throwable> 
asFailableFunction(final Method method) {
+        return asInterfaceInstance(FailableFunction.class, method);
+    }
+
+    /**
+     * Produces a {@link FailableSupplier} for a given a <em>supplier</em> 
Method. The FailableSupplier return type must
+     * match the method's return type.
+     * <p>
+     * Only works with static methods.
+     * </p>
+     *
+     * @param <R> The Method return type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <R> FailableSupplier<R, Throwable> asFailableSupplier(final 
Method method) {
+        return asInterfaceInstance(FailableSupplier.class, method);
+    }
+
+    /**
+     * Produces a {@link Function} for a given a <em>supplier</em> Method. You 
call the Function with one argument: the
+     * object receiving the method call. The Function return type must match 
the method's return type.
+     * <p>
+     * For example to invoke {@link String#length()}:
+     * </p>
+     *
+     * <pre>
+     * final Method method = String.class.getMethod("length");
+     * final Function&lt;String, Integer&gt; function = 
MethodInvokers.asFunction(method);
+     * assertEquals(3, function.apply("ABC"));
+     * </pre>
+     *
+     * @param <T> the type of the first argument to the function: The type 
containing the method.
+     * @param <R> the type of the result of the function: The method return 
type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, R> Function<T, R> asFunction(final Method method) {
+        return asInterfaceInstance(Function.class, method);
+    }
+
+    /**
+     * Produces an instance of the given single-method interface which 
redirects its calls to the given method.
+     * <p>
+     * For the definition of "single-method", see {@linkplain 
MethodHandleProxies#asInterfaceInstance(Class, MethodHandle)}.
+     * </p>
+     *
+     * @param <T> The interface type.
+     * @param intfc The interface type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     * @see MethodHandleProxies#asInterfaceInstance(Class, MethodHandle)
+     */
+    public static <T> T asInterfaceInstance(final Class<T> intfc, final Method 
method) {
+        return 
MethodHandleProxies.asInterfaceInstance(Objects.requireNonNull(intfc, "intfc"), 
unreflectUnchecked(method));
+    }
+
+    /**
+     * Produces a {@link Supplier} for a given a <em>supplier</em> Method. The 
Supplier return type must match the method's
+     * return type.
+     * <p>
+     * Only works with static methods.
+     * </p>
+     *
+     * @param <R> The Method return type.
+     * @param method the method to invoke.
+     * @return a correctly-typed wrapper for the given target.
+     */
+    @SuppressWarnings("unchecked")
+    public static <R> Supplier<R> asSupplier(final Method method) {
+        return asInterfaceInstance(Supplier.class, method);
+    }
+
+    /**
+     * Throws NullPointerException if {@code method} is {@code null}.
+     *
+     * @param method The method to test.
+     * @return The given method.
+     * @throws NullPointerException if {@code method} is {@code null}.
+     */
+    private static Method requireMethod(final Method method) {
+        return Objects.requireNonNull(method, "method");
+    }
+
+    private static MethodHandle unreflect(final Method method) throws 
IllegalAccessException {
+        return MethodHandles.lookup().unreflect(requireMethod(method));
+    }
+
+    private static MethodHandle unreflectUnchecked(final Method method) {
+        try {
+            return unreflect(method);
+        } catch (final IllegalAccessException e) {
+            throw new UncheckedIllegalAccessException(e);
+        }
+    }
+
+    /**
+     * No need to create instances.
+     */
+    private MethodInvokers() {
+        // noop
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/exception/CustomCheckedException.java 
b/src/test/java/org/apache/commons/lang3/exception/CustomCheckedException.java
new file mode 100644
index 0000000..9982d09
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/exception/CustomCheckedException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.exception;
+
+public class CustomCheckedException extends Exception {
+
+    public CustomCheckedException() {
+        super();
+    }
+
+    public CustomCheckedException(String message) {
+        super(message);
+    }
+
+    public CustomCheckedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CustomCheckedException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/exception/CustomUncheckedException.java
 
b/src/test/java/org/apache/commons/lang3/exception/CustomUncheckedException.java
new file mode 100644
index 0000000..fc53005
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/exception/CustomUncheckedException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.exception;
+
+public class CustomUncheckedException extends RuntimeException {
+
+    public CustomUncheckedException() {
+        super();
+    }
+
+    public CustomUncheckedException(String message) {
+        super(message);
+    }
+
+    public CustomUncheckedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CustomUncheckedException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/AnnotationTestFixture.java 
b/src/test/java/org/apache/commons/lang3/function/AnnotationTestFixture.java
new file mode 100644
index 0000000..a179a1f
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/function/AnnotationTestFixture.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@interface AnnotationTestFixture {
+    // empty
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodFixtures.java 
b/src/test/java/org/apache/commons/lang3/function/MethodFixtures.java
new file mode 100644
index 0000000..a7530d1
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/function/MethodFixtures.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.exception.CustomCheckedException;
+import org.apache.commons.lang3.exception.CustomUncheckedException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+
+class MethodFixtures {
+
+    static MethodFixtures INSTANCE = new MethodFixtures();
+
+    static Method getDeclaredMethod(final String name, final Class<?>... 
parameterTypes) throws NoSuchMethodException, SecurityException {
+        return MethodFixtures.class.getDeclaredMethod(name, parameterTypes);
+    }
+
+    static Method getMethodForGetString() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("getString");
+    }
+
+    static Method getMethodForGetString1Arg() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("getString1Arg", String.class);
+    }
+
+    static Method getMethodForGetString1ArgChecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("getString1ArgChecked", String.class);
+    }
+
+    static Method getMethodForGetString1ArgThrowsChecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("getString1ArgThrowsChecked", String.class);
+    }
+
+    static Method getMethodForGetString1ArgThrowsUnchecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("getString1ArgThrowsUnchecked", String.class);
+    }
+
+    static Method getMethodForGetString2Arg() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("getString2Args", String.class, String.class);
+    }
+
+    static Method getMethodForGetStringChecked() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("getStringChecked");
+    }
+
+    static Method getMethodForGetStringsVarArg() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("getStringArrayVarStringArgs", 
String[].class);
+    }
+
+    static Method getMethodForGetStringThrowsChecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("getStringThrowsChecked");
+    }
+
+    static Method getMethodForGetStringThrowsUnchecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("getStringThrowsUnchecked");
+    }
+
+    static Method getMethodForGetStringVarStringArgs() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("geStringtVarStringArgs", String[].class);
+    }
+
+    static Method getMethodForSetString1Arg() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("setValue1", String.class);
+    }
+
+    static Method getMethodForSetString1ArgThrows() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("setValue1Throws", String.class);
+    }
+
+    static Method getMethodForSetString1ArgThrowsChecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("setValue1ThrowsChecked", String.class);
+    }
+
+    static Method getMethodForSetString1ArgThrowsUnchecked() throws 
NoSuchMethodException, SecurityException {
+        return getDeclaredMethod("setValue1ThrowsUnchecked", String.class);
+    }
+
+    static Method getMethodForSetString2Args() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("setValue1And2", String.class, String.class);
+    }
+
+    static Method getMethodForSetStringsVarArg() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("setValueArray", String[].class);
+    }
+
+    static Method getMethodForStaticGetString() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("staticGetString");
+    }
+
+    static Method getMethodForVoidMethod() throws NoSuchMethodException, 
SecurityException {
+        return getDeclaredMethod("voidMethod");
+    }
+
+    public static String staticGetString() {
+        return "Static.ABC";
+    }
+
+    private String value1;
+
+    private String value2;
+
+    private String[] valueArray;
+
+    @BeforeEach
+    @AfterEach
+    public void clear() {
+        value1 = null;
+        value1 = null;
+        valueArray = null;
+    }
+
+    public String geStringtVarStringArgs(final String... strings) {
+        return "XYZ";
+    }
+
+    @AnnotationTestFixture
+    public String getString() {
+        return "ABC";
+    }
+
+    public String getString1Arg(final String value) {
+        return value;
+    }
+
+    @SuppressWarnings("unused") // IOException is declared but never thrown.
+    public String getString1ArgChecked(final String value) throws IOException {
+        return value;
+    }
+
+    public String getString1ArgThrowsChecked(final String value) throws 
CustomCheckedException {
+        throw new CustomCheckedException("getString1ArgThrowsChecked");
+    }
+
+    public String getString1ArgThrowsUnchecked(final String value) {
+        throw new CustomUncheckedException("getString1ArgThrowsUnchecked");
+    }
+
+    @AnnotationTestFixture
+    public String getString2() {
+        return "EFG";
+    }
+
+    public String getString2Args(final String value1, final String value2) {
+        return value1 + value2;
+    }
+
+    public String[] getStringArrayVarStringArgs(final String... strings) {
+        return strings;
+    }
+
+    public String getStringChecked() throws Exception {
+        return "ABC";
+    }
+
+    public String getStringThrowsChecked() throws CustomCheckedException {
+        throw new CustomCheckedException("getStringThrowsChecked");
+    }
+
+    public String getStringThrowsUnchecked() {
+        throw new CustomUncheckedException("getStringThrowsUnchecked");
+    }
+
+    String getValue1() {
+        return value1;
+    }
+
+    String getValue2() {
+        return value2;
+    }
+
+    String[] getValueArray() {
+        return valueArray;
+    }
+
+    void setValue1(final String value1) throws Exception {
+        this.value1 = value1;
+    }
+
+    void setValue1And2(final String value1, final String value2) throws 
Exception {
+        this.value1 = value1;
+        this.value2 = value2;
+    }
+
+    void setValue1ThrowsChecked(final String value1) throws 
CustomCheckedException {
+        throw new CustomCheckedException("setValue1ThrowsChecked");
+    }
+
+    void setValue1ThrowsUnchecked(final String value1) {
+        throw new CustomUncheckedException("setValue1ThrowsUnchecked");
+    }
+
+    void setValue2(final String value2) {
+        this.value2 = value2;
+    }
+
+    void setValueArray(final String... values) throws Exception {
+        this.valueArray = values;
+    }
+
+    public void voidMethod() {
+        // noop
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiConsumerTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiConsumerTest.java
new file mode 100644
index 0000000..9d02c24
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiConsumerTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+import java.util.function.BiConsumer;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asBiConsumer(Method)}.
+ */
+public class MethodInvokersBiConsumerTest extends MethodFixtures {
+
+    @Test
+    public void testApply1Arg() throws NoSuchMethodException, 
SecurityException {
+        final BiConsumer<Object, Object> biConsumer = 
MethodInvokers.asBiConsumer(getMethodForSetString1Arg());
+        biConsumer.accept(INSTANCE, "A");
+        assertEquals("A", INSTANCE.getValue1());
+        biConsumer.accept(INSTANCE, "B");
+        assertEquals("B", INSTANCE.getValue1());
+    }
+
+    @Test
+    public void testConstructorForNull() throws SecurityException {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asBiConsumer(null));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        final BiConsumer<Object, Object> biConsumer = 
MethodInvokers.asBiConsumer(getMethodForSetString1Arg());
+        assertFalse(biConsumer.toString().isEmpty());
+        assertFalse(biConsumer.toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiFunctionTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiFunctionTest.java
new file mode 100644
index 0000000..90c24ce
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersBiFunctionTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+import java.util.function.BiFunction;
+
+import org.apache.commons.lang3.exception.CustomUncheckedException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asBiFunction(Method)}.
+ */
+public class MethodInvokersBiFunctionTest extends MethodFixtures {
+
+    @Test
+    public void testApply1Arg() throws NoSuchMethodException, 
SecurityException {
+        final BiFunction<MethodFixtures, String, String> func = 
MethodInvokers.asBiFunction(getMethodForGetString1Arg());
+        assertEquals(INSTANCE.getString1Arg("A"), func.apply(INSTANCE, "A"));
+    }
+
+    @Test
+    public void testApply1ArgThrowsUnchecked() throws NoSuchMethodException, 
SecurityException {
+        final BiFunction<MethodFixtures, String, String> func = 
MethodInvokers.asBiFunction(getMethodForGetString1ArgThrowsUnchecked());
+        assertThrows(CustomUncheckedException.class, () -> 
func.apply(INSTANCE, "A"));
+    }
+
+    @Test
+    public void testConstructorForNull() throws SecurityException {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asBiFunction(null));
+    }
+
+    @Test
+    public void testFullExample() throws SecurityException, 
ReflectiveOperationException {
+        final Method method = String.class.getMethod("charAt", int.class);
+        final BiFunction<String, Integer, Character> function = 
MethodInvokers.asBiFunction(method);
+        assertEquals('C', function.apply("ABC", 2));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asBiFunction(getMethodForGetString1Arg()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiConsumerTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiConsumerTest.java
new file mode 100644
index 0000000..4d369d9
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiConsumerTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.exception.CustomCheckedException;
+import org.apache.commons.lang3.exception.CustomUncheckedException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asFailableBiConsumer(Method)}.
+ */
+public class MethodInvokersFailableBiConsumerTest extends MethodFixtures {
+
+    @Test
+    public void testApply1Arg() throws Throwable {
+        
MethodInvokers.asFailableBiConsumer(getMethodForSetString1Arg()).accept(INSTANCE,
 "A");
+        assertEquals("A", INSTANCE.getValue1());
+    }
+
+    @Test
+    public void testApply1ArgThrowsChecked() throws Exception {
+        assertThrows(CustomCheckedException.class, () -> 
MethodInvokers.asFailableBiConsumer(getMethodForSetString1ArgThrowsChecked()).accept(INSTANCE,
 "A"));
+    }
+
+    @Test
+    public void testApply1ArgThrowsUnchecked() throws Exception {
+        assertThrows(CustomUncheckedException.class, () -> 
MethodInvokers.asFailableBiConsumer(getMethodForSetString1ArgThrowsUnchecked()).accept(INSTANCE,
 "A"));
+    }
+
+    @Test
+    public void testConstructorForNull() throws Exception {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asFailableBiConsumer(null));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asFailableBiConsumer(getMethodForSetString1Arg()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiFunctionTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiFunctionTest.java
new file mode 100644
index 0000000..4b768cb
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableBiFunctionTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.exception.CustomCheckedException;
+import org.apache.commons.lang3.exception.CustomUncheckedException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asFailableBiFunction(Method)}.
+ */
+public class MethodInvokersFailableBiFunctionTest extends MethodFixtures {
+
+    @Test
+    public void testApply1Arg() throws Throwable {
+        // Use a local variable typed to the interface to make sure we compile.
+        final FailableBiFunction<MethodFixtures, String, String[], Throwable> 
func = MethodInvokers.asFailableBiFunction(getMethodForGetString1ArgChecked());
+        assertEquals(INSTANCE.getString1ArgChecked("A"), func.apply(INSTANCE, 
"A"));
+    }
+
+    @Test
+    public void testApply1ArgThrowsChecked() throws NoSuchMethodException, 
SecurityException {
+        // Use a local variable typed to the interface to make sure we compile.
+        final FailableBiFunction<MethodFixtures, String, String[], Throwable> 
func = MethodInvokers
+            .asFailableBiFunction(getMethodForGetString1ArgThrowsChecked());
+        assertThrows(CustomCheckedException.class, () -> func.apply(INSTANCE, 
"A"));
+    }
+
+    @Test
+    public void testApply1ArgThrowsUnchecked() throws NoSuchMethodException, 
SecurityException {
+        // Use a local variable typed to the interface to make sure we compile.
+        final FailableBiFunction<MethodFixtures, String, String[], Throwable> 
func = MethodInvokers
+            .asFailableBiFunction(getMethodForGetString1ArgThrowsUnchecked());
+        assertThrows(CustomUncheckedException.class, () -> 
func.apply(INSTANCE, "A"));
+    }
+
+    @Test
+    public void testConstructorForNull() throws SecurityException {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asFailableBiFunction(null));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, Throwable {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asFailableBiFunction(getMethodForGetString1ArgChecked()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableFunctionTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableFunctionTest.java
new file mode 100644
index 0000000..8e3ddf2
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableFunctionTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.exception.UncheckedException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asFailableFunction(Method)}.
+ */
+public class MethodInvokersFailableFunctionTest extends MethodFixtures {
+
+    @Test
+    public void testApply0Arg() throws Throwable {
+        assertEquals(INSTANCE.getString(), 
MethodInvokers.asFailableFunction(getMethodForGetString()).apply(INSTANCE));
+    }
+
+    @Test
+    public void testConstructorForNull() throws SecurityException {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asFailableFunction((Method) null));
+    }
+
+    @Test
+    public void testBuildVarArg() throws SecurityException, 
NoSuchMethodException {
+        
MethodInvokers.asFailableFunction(getMethodForGetStringVarStringArgs());
+    }
+
+    @Test
+    public void testFindAndInvoke() throws SecurityException {
+        // Finding
+        final List<FailableFunction<Object, Object, Throwable>> invokers = 
Stream.of(MethodFixtures.class.getDeclaredMethods())
+            .filter(m -> 
m.isAnnotationPresent(AnnotationTestFixture.class)).map(MethodInvokers::asFailableFunction).collect(Collectors.toList());
+        assertEquals(2, invokers.size());
+        // ...
+        // Invoking
+        final Set<Object> set = invokers.stream().map(i -> {
+            try {
+                return i.apply(MethodFixtures.INSTANCE);
+            } catch (final Throwable e) {
+                throw new UncheckedException(e);
+            }
+        }).collect(Collectors.toSet());
+        assertEquals(new HashSet<>(Arrays.asList(INSTANCE.getString(), 
INSTANCE.getString2())), set);
+    }
+
+    @Test
+    public void testThrowsChecked() throws Exception {
+        assertThrows(Exception.class, () -> 
MethodInvokers.asFailableFunction(getMethodForGetStringThrowsChecked()).apply(INSTANCE));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asFailableFunction(getMethodForGetString()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableSupplierTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableSupplierTest.java
new file mode 100644
index 0000000..62ccc60
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFailableSupplierTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.lang.reflect.Method;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asFailableSupplier(Method)}.
+ */
+public class MethodInvokersFailableSupplierTest extends MethodFixtures {
+
+    @Test
+    public void testSupplierStatic() throws Throwable {
+        assertEquals(staticGetString(), 
MethodInvokers.asFailableSupplier(getMethodForStaticGetString()).get());
+        assertEquals(staticGetString(), 
MethodInvokers.asFailableSupplier(getMethodForStaticGetString()).get());
+    }
+
+    @Test
+    public void testSupplierToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asFailableSupplier(getMethodForStaticGetString()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersFunctionTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFunctionTest.java
new file mode 100644
index 0000000..eb556f9
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersFunctionTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.exception.CustomUncheckedException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asFunction(Method)}.
+ */
+public class MethodInvokersFunctionTest extends MethodFixtures {
+
+    @Test
+    public void testApply0Arg() throws NoSuchMethodException, 
SecurityException {
+        final Function<MethodFixtures, String> func = 
MethodInvokers.asFunction(getMethodForGetString());
+        assertEquals(INSTANCE.getString(), func.apply(INSTANCE));
+    }
+
+    @Test
+    public void testApply0ArgThrowsUnchecked() throws NoSuchMethodException, 
SecurityException {
+        final Function<MethodFixtures, String> func = 
MethodInvokers.asFunction(getMethodForGetStringThrowsUnchecked());
+        assertThrows(CustomUncheckedException.class, () -> 
func.apply(INSTANCE));
+    }
+
+    @Test
+    public void testBuildVarArg() throws SecurityException, 
NoSuchMethodException {
+        MethodInvokers.asFunction(getMethodForGetStringVarStringArgs());
+    }
+
+    @Test
+    public void testConstructorForNull() throws SecurityException {
+        assertThrows(NullPointerException.class, () -> 
MethodInvokers.asFunction(null));
+    }
+
+    @Test
+    public void testFindAndInvoke() throws SecurityException {
+        // Finding
+        final List<Function<Object, Object>> invokers = 
Stream.of(MethodFixtures.class.getDeclaredMethods())
+            .filter(m -> 
m.isAnnotationPresent(AnnotationTestFixture.class)).map(MethodInvokers::asFunction).collect(Collectors.toList());
+        assertEquals(2, invokers.size());
+        // ...
+        // Invoking
+        final Set<Object> set1 = invokers.stream().map(i -> 
i.apply(MethodFixtures.INSTANCE)).collect(Collectors.toSet());
+        assertEquals(new HashSet<>(Arrays.asList(INSTANCE.getString(), 
INSTANCE.getString2())), set1);
+        final Set<Object> set2 = 
Stream.of(INSTANCE).map(invokers.get(0)).collect(Collectors.toSet());
+        final Set<Object> set3 = 
Stream.of(INSTANCE).map(invokers.get(1)).collect(Collectors.toSet());
+        set2.addAll(set3);
+        assertEquals(new HashSet<>(Arrays.asList(INSTANCE.getString(), 
INSTANCE.getString2())), set2);
+    }
+
+    @Test
+    public void testFullExample() throws SecurityException, 
ReflectiveOperationException {
+        final Method method = String.class.getMethod("length");
+        final Function<String, Integer> function = 
MethodInvokers.asFunction(method);
+        assertEquals(3, function.apply("ABC"));
+    }
+
+    @Test
+    public void testMapComputeIfAbsent() throws NoSuchMethodException, 
SecurityException {
+        final Map<MethodFixtures, String> map = new HashMap<>();
+        map.computeIfAbsent(INSTANCE, 
MethodInvokers.asFunction(getMethodForGetString()));
+        assertEquals(INSTANCE.getString(), map.get(INSTANCE));
+    }
+
+    @Test
+    public void testToString() throws SecurityException, 
ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        
assertFalse(MethodInvokers.asFunction(getMethodForGetString()).toString().isEmpty());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/commons/lang3/function/MethodInvokersSupplierTest.java
 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersSupplierTest.java
new file mode 100644
index 0000000..99ba067
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/lang3/function/MethodInvokersSupplierTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.lang.reflect.Method;
+import java.util.function.Supplier;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link MethodInvokers#asSupplier(Method)}.
+ */
+public class MethodInvokersSupplierTest extends MethodFixtures {
+
+    @Test
+    public void testSupplierStaticGetMethod() throws NoSuchMethodException, 
SecurityException {
+        final Supplier<String> supplier = 
MethodInvokers.asSupplier(getMethodForStaticGetString());
+        assertEquals(staticGetString(), supplier.get());
+        assertEquals(staticGetString(), supplier.get());
+    }
+
+    @Test
+    public void testSupplierStaticGetMethodToString() throws 
SecurityException, ReflectiveOperationException {
+        // Should not blow up and must return _something_
+        final Supplier<Object> supplier = 
MethodInvokers.asSupplier(getMethodForStaticGetString());
+        assertFalse(supplier.toString().isEmpty());
+        assertFalse(supplier.toString().isEmpty());
+    }
+
+}

Reply via email to