1

Why does this code snippet fail with IllegalArgumentException: wrong number of arguments? Demonstrated code works with ordinary member and static methods, as well as with native declared ones...

   public class Program {
        public static void main(String[] args) throws ReflectiveOperationException {
            //get native getDeclaredMethods method
            Method Class$getDeclaredMethods0 = Class.class.getDeclaredMethod("getDeclaredMethods0", boolean.class);
            Class$getDeclaredMethods0.setAccessible(true);

            //call main
            Method[] methods = (Method[]) Class$getDeclaredMethods0.invoke(Program.class, false);
            Method main = methods[0];
            main.invoke(null, args); // ← Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
            //at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            //at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
            //at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            //at java.lang.reflect.Method.invoke(Method.java:606)
            //at Program.main(Program.java:19)
            //at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            //at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
            //at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            //at java.lang.reflect.Method.invoke(Method.java:606)
            //at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
        }
    }
Binkan Salaryman
  • 3,008
  • 1
  • 17
  • 29
  • Why are you calling `getDeclaredMethods` by reflection rather than directly? And why are you assuming that there's only a single declared method, which must be `main`? – Jon Skeet Mar 03 '15 at 15:18
  • As addition - how to return static initializer, instance initializer, and default constructor as methods? – Binkan Salaryman Mar 03 '15 at 15:20
  • One question per post, please. (And what makes you think those are available *as* methods?) – Jon Skeet Mar 03 '15 at 15:20
  • Contructors are implemented as methods (in my opinion they are a bad design choice), and initializers are executable code. They have every aspect needed to be handled as methods - name, offset, visibility, parent – Binkan Salaryman Mar 03 '15 at 15:33
  • "Contructors are implemented as methods" - in what sense? (There are many possible senses here.) Reflection allows you to get at constructors directly, so why not do that? As for instance initializers - they *don't* have a name, and they're actually baked into each constructor. – Jon Skeet Mar 03 '15 at 15:36
  • An instance initializer's name is "" – Binkan Salaryman Mar 03 '15 at 15:38
  • Where are you seeing that? I just compiled an example with an instance initializer, and javap just showed the code within the initializer being duplicated within each declared constructor. Anyway, as suggested before, please ask a new question with details about what you're really trying to achieve. – Jon Skeet Mar 03 '15 at 15:40
  • Look here http://stackoverflow.com/questions/8517121/java-vmspec-what-is-difference-between-init-and-clinit?lq=1 and here http://www.informit.com/articles/article.aspx?p=2024315&seqNum=9 – Binkan Salaryman Mar 03 '15 at 15:43
  • That's saying that the *constructor* appears with that name. Not an instance initializer, (i.e. just `{ /* statements */ }` within a class declaration. – Jon Skeet Mar 03 '15 at 15:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72160/discussion-between-binkan-salaryman-and-jon-skeet). – Binkan Salaryman Mar 03 '15 at 15:46

1 Answers1

2

It's not clear why you're calling getDeclaredMethods via reflection, but the invocation of main is broken because you're trying to call it as if it had several String parameters - one per value in args. Instead, you want to pass a single argument, of type String[]. You can do that like this:

main.invoke(null, new Object[] { args });
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • It works, but a `String[]` is not a `Object...` - so why is there a need to put `new Object[]{...}` around? Is it covariance/contravariance? – Binkan Salaryman Mar 03 '15 at 15:28
  • @BinkanSalaryman: Yes it is - it's an `Object[]`. Try it: `Object[] x = new String[10];`. That's array covariance for you. (`Object...` isn't really a type - it's just `Object[]` with a flag saying "This parameter is varargs...") – Jon Skeet Mar 03 '15 at 15:29