Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call method which takes an array using reflection

Tags:

java

arrays

Consider the following complete Java program.

public class Reflection
{

  static class A
  {
    public void useArray( String[] args )
    {
        System.out.println( "Args are " + Arrays.toString( args ) );
    }
  }

  public static void main( String[] args ) throws Exception
  { 
    Method m = A.class.getMethod( "useArray", String[].class );
    m.invoke( new A(), new String[] { "Hi" } );
  }

}

Trying to run this, you get an error:

Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch

If instead of using only one String in the array passed to invoke you pass more than one, then you get:

Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments

So, clearly, because invoke's signature is:

invoke(java.lang.Object obj, java.lang.Object... args)

when I call invoke using an array, the call is getting "translated" to:

m.invoke( new A(), "Hi" );

How to make Java understand that I do want my array to be passed into invoke intact??

like image 645
Renato Avatar asked Nov 24 '25 00:11

Renato


1 Answers

Some general info

The Method#invoke has two parameters

  1. Object obj which takes object on which method should be invoked
  2. Object... args which takes Object[] array holding all arguments for method.

So if we want to call method like methodName(foo, bar, baz) the Object... args should end up becoming new Object[]{foo, bar, baz}.

Similarly since useArray expects one argument which is String[] array itself, the Object... args should end up wrapping that array and becoming new Object[]{ new String[]{"Hi"} }

Solution

We can achieve that via explicitly writing

m.invoke(new A(), new Object[]{ new String[]{ "Hi" } });
//                ^^^^^^^^^^^^^----------------------^

OR

by telling compiler to treat String[] as single Object to let varargs wrap it inside new Object[]{...} array for us. We can achieve that by casting

m.invoke(new A(), (Object) new String[]{"Hi"});
//                ^^^^^^^^

Problem with your code

The String[] array is subtype of Object[]. This means that it ends up being assigned as value of args like

Object... args = new String[]{"Hi"};

instead of being wrapped by Object[] array like

Object... args = new Object[]{ new String[]{"Hi"} };

Because of that you end up with code representing new A().useArray("Hi").

But since useArray method expects String[] array and not String you are getting java.lang.IllegalArgumentException: argument type mismatch exception.

like image 112
Pshemo Avatar answered Nov 26 '25 15:11

Pshemo