16

I am attempting to write a method the executes a static method from another class by passing an array of strings as arguments to the method.

Here's what I have:

public static void
executeStaticCommand(final String[] command, Class<?> provider)
{
    Method[] validMethods = provider.getMethods();

    String javaCommand = TextFormat.toCamelCase(command[0]);

    for (Method method : validMethods) {
        if (method.getName().equals(javaCommand)) {
            try {
                method.invoke(null, new Object[] { new Object[] { command } });
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                Throwable ex = e.getCause();
                ex.printStackTrace();
            }
            break;
        }
    }
}

Such that this:

String[] args = new String[] { "methodName", "arg1", "arg2" }; 
executeStaticCommand(args, ClassName.class);

Should execute this:

public class ClassName {
    public static void methodName(String[] args) {
        assert args[1].equals("arg1");
    }
}

However I'm getting IllegalArgumentExceptions.

Andremoniy
  • 34,031
  • 20
  • 135
  • 241
azz
  • 5,852
  • 3
  • 30
  • 58

3 Answers3

24

You have two problems:

  1. The target parameter type is String[], but you're passing in a Object[]
  2. You're passing in the whole command array as arguments, which includes the method name

The problems are all in the inner try block, so I show only that code.

String[] args = Arrays.copyOfRange(command, 1, command.length - 1);
method.invoke(null, new Object[]{args}); // must prevent expansion into varargs

Thanks to Perception for reminding me of the varargs issue

Community
  • 1
  • 1
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    Was just typing this up, plus one additional enhancement he can make. You need to change the invoke to `method.invoke(null, new Object[] {args})` for this to work. – Perception Apr 11 '13 at 14:49
  • @Perception but the target method parameter is `String[]`, not `String, String`. Won't this work (I don't have a java editor handy here)? – Bohemian Apr 11 '13 at 14:53
  • 2
    It doesnt work because the array gets expanded into the varargs, causing both the signature and argument types to mismatch. – Perception Apr 11 '13 at 14:55
  • Point 2 is intentional, and `method.invoke(null, new Object[]{ command });` is what I originally had (before wrapping it in another `new Object[]{}`). It only works when there is one element in the `String[]` array. – azz Apr 11 '13 at 15:02
  • Can you try Pshemo's suggestion of `(Object)args`? Also, passing in the method name as a parameter to the method seems a bad idea. Why would the method want to be passed its own name? – Bohemian Apr 11 '13 at 15:08
  • Never mind... It turns out the issue was with the way I was building the array of Strings from STDIN. I was accidentally including the space between the end of each argument and the next. This works after all, but the problem was elsewhere... – azz Apr 11 '13 at 15:10
1

The method your trying to invoke is expecting String array, however you are passing Object array as param. Change it to String array Or you can pass any type if the method expects Object.

method.invoke(null,(Object) command );

Lavanya
  • 319
  • 1
  • 6
  • When I use `(Object)command`, if `command.length` is 1, the method is correctly called, bit if it is `> 1`, no method is called. – azz Apr 11 '13 at 14:47
0

Based on this question, it looks like the call should be

 method.invoke(null, command);
Community
  • 1
  • 1
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69