IllegalArgumentException when passing an Array as parameter during method invocation

I must miss something very fundamental. When I try to pass an array of any kind during a method invocation I get an error. However when I do it normally it works.

This is the complete code that fails

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {

        // Normal
        MyClass.sayHello(new String[] {"StackOverflow"});

        // Reflection
        Method m = MyClass.class.getMethod("sayHello", String[].class);
        m.invoke(null, new String[]{"StackOverflow"});
    }

    static class MyClass {
        public static void sayHello(String[] args) {
            System.out.println("Hello " + args[0]);
        }
    }
}

The Exception thrown

Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at Main.main(Main.java:11)

String... does not work either btw.

Jon Skeet
people
quotationmark

The problem is that the second parameter to invoke is meant to be an array of arguments - you're only specifying a single argument.

In most cases that would be okay as the second parameter of Method.invoke is a varargs parameter, but as your argument is already an array compatible with Object[], the compiler isn't creating a wrapper array. I'd expect you to get a compile-time warning like this:

Main.java:11: warning: non-varargs call of varargs method with inexact argument type for
                       last parameter;
        m.invoke(null, new String[]{"StackOverflow"});
                       ^
  cast to Object for a varargs call
  cast to Object[] for a non-varargs call and to suppress this warning

You could either explicitly create an array wrapping the argument, or cast the argument to Object so that the compiler needs to wrap it itself:

// Creates the wrapper array explicitly
m.invoke(null, new Object[] { new String[] { "StackOverflow" } });

or

// Compiler creates the wrapper array because the argument type is just Object
m.invoke(null, (Object) new String[] { "StackOverflow" });

people

See more on this question at Stackoverflow