/** * Tries to find a 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, 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(Object instance, String methodName, Object argument) { if (argument instanceof List) { List<?> arguments = (List<?>) argument; // ambiguous case: we can't tell if the user is using the multi-parameter syntax, or the single-parameter // syntax for a method which takes a List parameter. So we try one, then fall back to the other. Maybe<?> maybe = tryFindAndInvokeMultiParameterMethod(instance, methodName, arguments); if (maybe.isAbsent()) maybe = tryFindAndInvokeSingleParameterMethod(instance, methodName, argument); return maybe; } else { return tryFindAndInvokeSingleParameterMethod(instance, methodName, argument); } } }
/** * 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 * from the given list of arguments. * * @param methodName name of the method * @param arguments arguments that is intended to be given * @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)); }
/** * 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); }
@Test public void testTryFindAndInvokeSingleCollectionParameterMethod() throws Exception { TestClass instance = new TestClass(); Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42")); assertTrue(maybe.isPresent()); assertTrue(instance.wasSingleCollectionParameterMethodCalled()); }
@Test public void testMatchSingleParameterMethod() throws Exception { Predicate<Method> predicate = MethodCoercions.matchSingleParameterMethod("singleParameterMethod", "42"); assertTrue(predicate.apply(singleParameterMethod)); assertFalse(predicate.apply(multiParameterMethod)); assertFalse(predicate.apply(singleCollectionParameterMethod)); }
@Test public void testMatchMultiParameterMethod() throws Exception { Predicate<Method> predicate = MethodCoercions.matchMultiParameterMethod("multiParameterMethod", 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")); assertTrue(maybe.isPresent()); assertTrue(instance.wasMultiParameterMethodCalled()); }
@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 public void testTryFindAndInvokeBestMatchingMethodOnPrivateClassWithPublicSuper() throws Exception { PrivateClass instance = new PrivateClass(); Maybe<?> maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "methodOnSuperClass", "42"); assertTrue(maybe.isPresent()); assertTrue(instance.wasMethodOnSuperClassCalled()); Maybe<?> maybe2 = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "methodOnInterface", "42"); assertTrue(maybe2.isPresent()); assertTrue(instance.wasMethodOnInterfaceCalled()); }
@Test 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 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 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 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"); assertTrue(maybe.isPresent()); assertTrue(instance.wasSingleParameterMethodCalled()); instance = new TestClass(); maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42")); assertTrue(maybe.isPresent()); assertTrue(instance.wasMultiParameterMethodCalled()); instance = new TestClass(); maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("fred", "joe")); assertTrue(maybe.isPresent()); assertTrue(instance.wasSingleCollectionParameterMethodCalled()); }
@Test public void testPrivateBuilderClass() throws Exception { org.apache.brooklyn.location.jclouds.JcloudsTypeCoercionsWithBuilderTest.MyClazzWithBuilderReturningPrivateClass.Builder builder = MyClazzWithBuilderReturningPrivateClass.builder(); MethodCoercions.tryFindAndInvokeSingleParameterMethod(builder, "arg1", "val1").get(); assertEquals( coerce(ImmutableMap.of("arg1", "val1"), MyClazzWithBuilderReturningPrivateClass.class), MyClazzWithBuilderReturningPrivateClass.builder().arg1("val1").build()); }
/** * Tries to find a single-parameter method with a parameter compatible with (can be coerced to) the argument, and * invokes it. * * @param instance the object to invoke the method on * @param methodName the name of the method to invoke * @param argument the argument to the method's parameter. * @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<?> tryFindAndInvokeSingleParameterMethod(final Object instance, final String methodName, final Object argument) { Class<?> clazz = instance.getClass(); Iterable<Method> methods = Arrays.asList(clazz.getMethods()); Optional<Method> matchingMethod = Iterables.tryFind(methods, matchSingleParameterMethod(methodName, argument)); if (matchingMethod.isPresent()) { Method method = matchingMethod.get(); Method accessibleMethod = Reflections.findAccessibleMethod(method).get(); try { Type paramType = method.getGenericParameterTypes()[0]; Object coercedArgument = TypeCoercions.coerce(argument, TypeToken.of(paramType)); return Maybe.of(accessibleMethod.invoke(instance, coercedArgument)); } catch (IllegalAccessException | InvocationTargetException e) { throw Exceptions.propagate(e); } } else { return Maybe.absent(); } }
Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(arguments)); if (matchingMethod.isPresent()) { Method method = matchingMethod.get();