MethodCoercions: add more utility methods
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/8a832de5 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/8a832de5 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/8a832de5 Branch: refs/heads/master Commit: 8a832de59c513d81c4e8c97e723fc03f0aadf26a Parents: b945fdc Author: Aled Sage <aled.s...@gmail.com> Authored: Mon May 22 18:09:15 2017 +0100 Committer: Aled Sage <aled.s...@gmail.com> Committed: Tue May 23 14:45:33 2017 +0100 ---------------------------------------------------------------------- .../util/core/flags/MethodCoercions.java | 84 +++++++++++++++----- .../util/core/flags/MethodCoercionsTest.java | 83 ++++++++++++++----- 2 files changed, 125 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8a832de5/core/src/main/java/org/apache/brooklyn/util/core/flags/MethodCoercions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/MethodCoercions.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/MethodCoercions.java index a243581..b0afcdd 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/flags/MethodCoercions.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/MethodCoercions.java @@ -18,15 +18,7 @@ */ package org.apache.brooklyn.util.core.flags; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.reflect.TypeToken; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.guava.Maybe; +import static com.google.common.base.Preconditions.checkNotNull; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -34,7 +26,16 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; -import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.reflect.TypeToken; /** * A way of binding a loosely-specified method call into a strongly-typed Java method call. @@ -93,7 +94,7 @@ public class MethodCoercions { return Maybe.absent(); } } - + /** * Returns a predicate that matches a method with the given name, and parameters that * {@link org.apache.brooklyn.util.core.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process @@ -104,21 +105,48 @@ public class MethodCoercions { * @return a predicate that will match a compatible method */ public static Predicate<Method> matchMultiParameterMethod(final String methodName, final List<?> arguments) { + return Predicates.and(matchMethodByName(methodName), matchMultiParameterMethod(arguments)); + } + + /** + * Returns a predicate that matches a method with the given name. + * + * @param methodName name of the method + * @return a predicate that will match a compatible method + */ + public static Predicate<Method> matchMethodByName(final String methodName) { checkNotNull(methodName, "methodName"); + + return new Predicate<Method>() { + @Override + public boolean apply(@Nullable Method input) { + return (input != null) && input.getName().equals(methodName); + } + }; + } + + /** + * Returns a predicate that matches a method with parameters that + * {@link org.apache.brooklyn.util.core.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process + * from the given list of arguments. + * + * @param arguments arguments that is intended to be given + * @return a predicate that will match a compatible method + */ + public static Predicate<Method> matchMultiParameterMethod(final List<?> arguments) { checkNotNull(arguments, "arguments"); return new Predicate<Method>() { @Override public boolean apply(@Nullable Method input) { if (input == null) return false; - if (!input.getName().equals(methodName)) return false; int numOptionParams = arguments.size(); Type[] parameterTypes = input.getGenericParameterTypes(); if (parameterTypes.length != numOptionParams) return false; for (int paramCount = 0; paramCount < numOptionParams; paramCount++) { if (!TypeCoercions.tryCoerce(((List<?>) arguments).get(paramCount), - TypeToken.of(parameterTypes[paramCount])).isPresentAndNonNull()) return false; + TypeToken.of(parameterTypes[paramCount])).isPresent()) return false; } return true; } @@ -129,15 +157,13 @@ public class MethodCoercions { * Tries to find a multiple-parameter method with each parameter compatible with (can be coerced to) the * corresponding argument, and invokes it. * - * @param instance the object to invoke the method on - * @param methodName the name of the method to invoke + * @param instanceOrClazz the object or class to invoke the method on + * @param methods the methods to choose from * @param argument a list of the arguments to the method's parameters. * @return the result of the method call, or {@link org.apache.brooklyn.util.guava.Maybe#absent()} if method could not be matched. */ - public static Maybe<?> tryFindAndInvokeMultiParameterMethod(final Object instance, final String methodName, final List<?> arguments) { - Class<?> clazz = instance.getClass(); - Iterable<Method> methods = Arrays.asList(clazz.getMethods()); - Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(methodName, arguments)); + public static Maybe<?> tryFindAndInvokeMultiParameterMethod(Object instanceOrClazz, Iterable<Method> methods, List<?> arguments) { + Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(arguments)); if (matchingMethod.isPresent()) { Method method = matchingMethod.get(); try { @@ -148,7 +174,7 @@ public class MethodCoercions { Type paramType = method.getGenericParameterTypes()[paramCount]; coercedArguments[paramCount] = TypeCoercions.coerce(argument, TypeToken.of(paramType)); } - return Maybe.of(method.invoke(instance, coercedArguments)); + return Maybe.of(method.invoke(instanceOrClazz, coercedArguments)); } catch (IllegalAccessException | InvocationTargetException e) { throw Exceptions.propagate(e); } @@ -156,6 +182,21 @@ public class MethodCoercions { return Maybe.absent(); } } + + /** + * Tries to find a multiple-parameter method with each parameter compatible with (can be coerced to) the + * corresponding argument, and invokes it. + * + * @param instance the object to invoke the method on + * @param methodName the name of the method to invoke + * @param argument a list of the arguments to the method's parameters. + * @return the result of the method call, or {@link org.apache.brooklyn.util.guava.Maybe#absent()} if method could not be matched. + */ + public static Maybe<?> tryFindAndInvokeMultiParameterMethod(Object instance, String methodName, List<?> arguments) { + Class<?> clazz = instance.getClass(); + Iterable<Method> methods = Iterables.filter(Arrays.asList(clazz.getMethods()), matchMethodByName(methodName)); + return tryFindAndInvokeMultiParameterMethod(instance, methods, arguments); + } /** * Tries to find a method with each parameter compatible with (can be coerced to) the corresponding argument, and invokes it. @@ -165,7 +206,7 @@ public class MethodCoercions { * @param argument a list of the arguments to the method's parameters, or a single argument for a single-parameter method. * @return the result of the method call, or {@link org.apache.brooklyn.util.guava.Maybe#absent()} if method could not be matched. */ - public static Maybe<?> tryFindAndInvokeBestMatchingMethod(final Object instance, final String methodName, final Object argument) { + public static Maybe<?> tryFindAndInvokeBestMatchingMethod(Object instance, String methodName, Object argument) { if (argument instanceof List) { List<?> arguments = (List<?>) argument; @@ -181,5 +222,4 @@ public class MethodCoercions { return tryFindAndInvokeSingleParameterMethod(instance, methodName, argument); } } - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8a832de5/core/src/test/java/org/apache/brooklyn/util/core/flags/MethodCoercionsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/flags/MethodCoercionsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/flags/MethodCoercionsTest.java index e48d2b6..57adb54 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/flags/MethodCoercionsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/flags/MethodCoercionsTest.java @@ -18,22 +18,23 @@ */ package org.apache.brooklyn.util.core.flags; -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableList; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.lang.reflect.Method; +import java.util.List; -import org.apache.brooklyn.util.core.flags.MethodCoercions; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.lang.reflect.Method; -import java.util.List; - -import static org.testng.Assert.*; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; public class MethodCoercionsTest { + private Method staticMultiParameterMethod; private Method singleParameterMethod; private Method multiParameterMethod; private Method singleCollectionParameterMethod; @@ -41,6 +42,7 @@ public class MethodCoercionsTest { @BeforeClass public void testFixtureSetUp() { try { + staticMultiParameterMethod = TestClass.class.getMethod("staticMultiParameterMethod", boolean.class, int.class); singleParameterMethod = TestClass.class.getMethod("singleParameterMethod", int.class); multiParameterMethod = TestClass.class.getMethod("multiParameterMethod", boolean.class, int.class); singleCollectionParameterMethod = TestClass.class.getMethod("singleCollectionParameterMethod", List.class); @@ -58,11 +60,19 @@ public class MethodCoercionsTest { } @Test - public void testTryFindAndInvokeSingleParameterMethod() throws Exception { - TestClass instance = new TestClass(); - Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleParameterMethod", "42"); - assertTrue(maybe.isPresent()); - assertTrue(instance.wasSingleParameterMethodCalled()); + public void testMatchSingleCollectionParameterMethod() throws Exception { + Predicate<Method> predicate = MethodCoercions.matchSingleParameterMethod("singleCollectionParameterMethod", ImmutableList.of("42")); + assertFalse(predicate.apply(singleParameterMethod)); + assertFalse(predicate.apply(multiParameterMethod)); + assertTrue(predicate.apply(singleCollectionParameterMethod)); + } + + @Test + public void testMatchMethodByName() throws Exception { + Predicate<Method> predicate = MethodCoercions.matchMethodByName("singleParameterMethod"); + assertTrue(predicate.apply(singleParameterMethod)); + assertFalse(predicate.apply(multiParameterMethod)); + assertFalse(predicate.apply(singleCollectionParameterMethod)); } @Test @@ -74,6 +84,14 @@ public class MethodCoercionsTest { } @Test + public void testMatchMultiParameterMethodWithoutName() throws Exception { + Predicate<Method> predicate = MethodCoercions.matchMultiParameterMethod(ImmutableList.of("true", "42")); + assertFalse(predicate.apply(singleParameterMethod)); + assertTrue(predicate.apply(multiParameterMethod)); + assertFalse(predicate.apply(singleCollectionParameterMethod)); + } + + @Test public void testTryFindAndInvokeMultiParameterMethod() throws Exception { TestClass instance = new TestClass(); Maybe<?> maybe = MethodCoercions.tryFindAndInvokeMultiParameterMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42")); @@ -82,6 +100,17 @@ public class MethodCoercionsTest { } @Test + public void testTryFindAndInvokeStaticMultiParameterMethod() throws Exception { + try { + Maybe<?> maybe = MethodCoercions.tryFindAndInvokeMultiParameterMethod(TestClass.class, ImmutableList.of(staticMultiParameterMethod), ImmutableList.of("true", "42")); + assertTrue(maybe.isPresent()); + assertTrue(TestClass.wasStaticMultiParameterMethodCalled()); + } finally { + TestClass.clear(); + } + } + + @Test public void testTryFindAndInvokeBestMatchingMethod() throws Exception { TestClass instance = new TestClass(); Maybe<?> maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleParameterMethod", "42"); @@ -98,29 +127,43 @@ public class MethodCoercionsTest { assertTrue(maybe.isPresent()); assertTrue(instance.wasSingleCollectionParameterMethodCalled()); } -/* + @Test - public void testMatchSingleCollectionParameterMethod() throws Exception { - Predicate<Method> predicate = MethodCoercions.matchSingleCollectionParameterMethod("singleCollectionParameterMethod", ImmutableList.of("42")); - assertFalse(predicate.apply(singleParameterMethod)); - assertFalse(predicate.apply(multiParameterMethod)); - assertTrue(predicate.apply(singleCollectionParameterMethod)); + public void testTryFindAndInvokeSingleParameterMethod() throws Exception { + TestClass instance = new TestClass(); + Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleParameterMethod", "42"); + assertTrue(maybe.isPresent()); + assertTrue(instance.wasSingleParameterMethodCalled()); } @Test public void testTryFindAndInvokeSingleCollectionParameterMethod() throws Exception { TestClass instance = new TestClass(); - Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleCollectionParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42")); + Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42")); assertTrue(maybe.isPresent()); assertTrue(instance.wasSingleCollectionParameterMethodCalled()); } -*/ + public static class TestClass { + private static boolean staticMultiParameterMethodCalled; + private boolean singleParameterMethodCalled; private boolean multiParameterMethodCalled; private boolean singleCollectionParameterMethodCalled; + public static void staticMultiParameterMethod(boolean parameter1, int parameter2) { + staticMultiParameterMethodCalled = true; + } + + public static boolean wasStaticMultiParameterMethodCalled() { + return staticMultiParameterMethodCalled; + } + + public static void clear() { + staticMultiParameterMethodCalled = false; + } + public void singleParameterMethod(int parameter) { singleParameterMethodCalled = true; }