Java argument type mismatch while reflection

2019-07-17 01:34发布

I am trying to run some method I load from another jar, that returns an integer, and then I want to return it to another class and pass it to my logic.

I made my method loading class pretty simple like this:

public class ModuleLoader {

    private Class<?> cls;

    public void initializeCommandModule(Module m) throws Exception {
        URL url = this.getURL(m.getJar());
        this.cls = this.loadClass(m.getMainClass(), url);
    }

    public int execute(Module m, ArrayList<String> args) throws Exception {
        Method method = this.cls.getDeclaredMethod("execute", ArrayList.class);
        return (int) method.invoke(this.cls.newInstance(), 1);
    }

    public int respond(ArrayList<String> args) throws Exception {
        Method method = this.cls.getDeclaredMethod("response", ArrayList.class);
        return (int) method.invoke(this.cls.newInstance(), 1);
    }

    private Class<?> loadClass(String cls, URL url) throws ClassNotFoundException, IOException {
        URLClassLoader loader = new URLClassLoader(new URL[]{url});
        Class<?> toReturn = loader.loadClass(cls);
        loader.close();

        return toReturn;
    }

    private URL getURL(String jar) throws MalformedURLException {
        return new File(jar).toURI().toURL();
    }

}

Take a look at the execute(Module m, ArrayList<String> args) method, this line throws the error:

    return (int) method.invoke(this.cls.newInstance());

The jar library I load looks like this:

public class Test {

    public int execute(ArrayList<String> i) {
        System.out.println("Hello world!");
        return 0;
    }

}

Why when I run that method I get the following exception thrown?

Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at ben.console.modules.ModuleLoader.execute(ModuleLoader.java:24)
    at ben.console.CommandProcessor.process(CommandProcessor.java:37)
    at ben.console.Console.listen(Console.java:25)
    at ben.console.Console.main(Console.java:31)

Thanks in advice!

3条回答
我命由我不由天
2楼-- · 2019-07-17 02:14

In your execute() method, you have this

return (int) method.invoke(this.cls.newInstance());

I think you wanted

return (int) method.invoke(this, args);

Likewise with respond(),

Method method = this.cls.getDeclaredMethod("response", ArrayList.class);
return (int) method.invoke(this.cls.newInstance(), 1);

should be

return (int) method.invoke(this, args);

You may find my blog post here helpful.

查看更多
Anthone
3楼-- · 2019-07-17 02:25

As far as I understand you fetch method that accepts one argument of type ArrayList:

Method method = this.cls.getDeclaredMethod("execute", ArrayList.class);

But then try to invoke it with argument of type that I cannot recognize that is obviously not ArrayList

(int) method.invoke(this.cls.newInstance()); 

What is the type of this.cls.newInstance()? Value of cls is assigned in method initializeCommandModule() as following:

this.cls = this.loadClass(m.getMainClass(), url);

where m is Module. I have no idea what Module is and therefore do not know what does getMainClass() return.

查看更多
仙女界的扛把子
4楼-- · 2019-07-17 02:27

You forgot to pass an argument to your method invocation.

return (int) method.invoke(this.cls.newInstance(), myArrayList);

You can also invoke with a null argument:

return (int) method.invoke(this.cls.newInstance(), (Object[])null);
查看更多
登录 后发表回答