Split Reflections.invokeMethodArgs into Method find and Method invoke Gives more control over what method gets executed.
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/eb4ac4c1 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/eb4ac4c1 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/eb4ac4c1 Branch: refs/heads/master Commit: eb4ac4c1493a563982c98eb8cbd97e47bf9a6700 Parents: 6607ccb Author: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com> Authored: Tue Dec 13 11:11:41 2016 +0200 Committer: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com> Committed: Tue Dec 13 11:11:41 2016 +0200 ---------------------------------------------------------------------- .../brooklyn/util/javalang/Reflections.java | 72 ++++++++++++++++---- .../brooklyn/util/javalang/ReflectionsTest.java | 18 +++++ 2 files changed, 75 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eb4ac4c1/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java index 95bbf7f..fba72b5 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java @@ -842,18 +842,26 @@ public class Reflections { } /** as {@link #invokeMethodFromArgs(Object, String, List)} but giving control over whether to set it accessible */ public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<?> args, boolean setAccessible) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Maybe<Method> maybeMethod = getMethodFromArgs(clazzOrInstance, method, args); + if (maybeMethod.isAbsent()) { + return Maybe.absent(Maybe.getException(maybeMethod)); + } + Method m = maybeMethod.get(); + + return Maybe.of(invokeMethodFromArgs(clazzOrInstance, m, args, setAccessible)); + } + + /** searches for the given method on the given clazz or instance, doing reasonably good matching on args etc */ + public static Maybe<Method> getMethodFromArgs(Object clazzOrInstance, String method, List<?> args) { Preconditions.checkNotNull(clazzOrInstance, "clazz or instance"); Preconditions.checkNotNull(method, "method"); Preconditions.checkNotNull(args, "args to "+method); Class<?> clazz; - Object instance; if (clazzOrInstance instanceof Class) { clazz = (Class<?>)clazzOrInstance; - instance = null; } else { clazz = clazzOrInstance.getClass(); - instance = clazzOrInstance; } Object[] argsArray = args.toArray(); @@ -873,25 +881,16 @@ public class Reflections { } } if (varargsMatch) { - Object varargs = Array.newInstance(varargType, argsArray.length+1 - parameterTypes.length); - for (int i=parameterTypes.length-1; i<argsArray.length; i++) { - Boxing.setInArray(varargs, i+1-parameterTypes.length, argsArray[i], varargType); - } - Object[] newArgsArray = new Object[parameterTypes.length]; - System.arraycopy(argsArray, 0, newArgsArray, 0, parameterTypes.length-1); - newArgsArray[parameterTypes.length-1] = varargs; - if (setAccessible) m.setAccessible(true); - return Maybe.of(m.invoke(instance, newArgsArray)); + return Maybe.of(m); } } } if (typesMatch(argsArray, parameterTypes)) { - if (setAccessible) m.setAccessible(true); - return Maybe.of(m.invoke(instance, argsArray)); + return Maybe.of(m); } } } - + List<String> argTypes = Lists.newArrayList(); for (Object arg : args) { argTypes.add(arg == null ? "<null>" : arg.getClass().getSimpleName()); @@ -899,6 +898,49 @@ public class Reflections { return Maybe.absent("Method '"+method+"' not found matching given args of type "+argTypes); } + /** invokes the given method on the given clazz or instance, assuming that the method matches passed arguments + * @throws InvocationTargetException + * @throws IllegalAccessException + * @throws IllegalArgumentException */ + public static Object invokeMethodFromArgs(Object clazzOrInstance, Method m, List<?> args) + throws IllegalAccessException, InvocationTargetException { + return invokeMethodFromArgs(clazzOrInstance, m, args, false); + } + + /** as {@link #invokeMethodFromArgs(Object, Method, List)} but giving control over whether to set it accessible */ + public static Object invokeMethodFromArgs(Object clazzOrInstance, Method m, List<?> args, boolean setAccessible) + throws IllegalAccessException, InvocationTargetException { + Preconditions.checkNotNull(clazzOrInstance, "clazz or instance"); + Preconditions.checkNotNull(m, "method"); + Preconditions.checkNotNull(args, "args to "+m); + + Object instance; + if (clazzOrInstance instanceof Class) { + instance = null; + } else { + instance = clazzOrInstance; + } + + Object[] argsArray = args.toArray(); + + Class<?>[] parameterTypes = m.getParameterTypes(); + if (m.isVarArgs()) { + Class<?> varargType = parameterTypes[parameterTypes.length-1].getComponentType(); + Object varargs = Array.newInstance(varargType, argsArray.length+1 - parameterTypes.length); + for (int i=parameterTypes.length-1; i<argsArray.length; i++) { + Boxing.setInArray(varargs, i+1-parameterTypes.length, argsArray[i], varargType); + } + Object[] newArgsArray = new Object[parameterTypes.length]; + System.arraycopy(argsArray, 0, newArgsArray, 0, parameterTypes.length-1); + newArgsArray[parameterTypes.length-1] = varargs; + if (setAccessible) m.setAccessible(true); + return m.invoke(instance, newArgsArray); + } else { + if (setAccessible) m.setAccessible(true); + return m.invoke(instance, argsArray); + } + } + /** true iff all args match the corresponding types */ public static boolean typesMatch(Object[] argsArray, Class<?>[] parameterTypes) { if (argsArray.length != parameterTypes.length) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eb4ac4c1/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java ---------------------------------------------------------------------- diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java index b6bb63c..b7d3975 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java @@ -129,6 +129,24 @@ public class ReflectionsTest { } @Test + public void testMethodInvocation() throws Exception { + Method m1Short = CI1.class.getMethod("m1", String.class, int.class); + Method m1Long = CI1.class.getMethod("m1", String.class, int.class, int.class, int[].class); + + Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, m1Short, Arrays.<Object>asList("hello", 3)), "hello3"); + Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, m1Long, Arrays.<Object>asList("hello", 3, 4, 5)), "hello12"); + } + + @Test + public void testGetMethod() throws Exception { + Method m1Short = CI1.class.getMethod("m1", String.class, int.class); + Method m1Long = CI1.class.getMethod("m1", String.class, int.class, int.class, int[].class); + + Assert.assertEquals(Reflections.getMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3)).get(), m1Short); + Assert.assertEquals(Reflections.getMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3, 4, 5)).get(), m1Long); + } + + @Test public void testConstruction() throws Exception { Assert.assertEquals(Reflections.invokeConstructorFromArgs(CI1.class, new Object[] {"hello", 3}).get().constructorArgs, ImmutableList.of("hello", 3)); Assert.assertEquals(Reflections.invokeConstructorFromArgs(CI1.class, new Object[] {"hello", 3, 4, 5}).get().constructorArgs, ImmutableList.of("hello", 3, 4, 5));