1

I am following this question How to generically implement calling methods stored in a HashMap? I am trying to pass parameters while calling executeCommand function Example code is as follows, InvokesMethodItf

public interface InvokesMethodItf {

public void invokeMethod(String data) throws Exception; //pass the data as parameter
public void setMethod(Method method);
} 

InvokesMethod

public class InvokesMethod implements InvokesMethodItf{

private Method method;

@Override
public void invokeMethod(String data) throws Exception {
     method.invoke(data);    //pass the data to invoke (I think my problem is here). I dont know how to pass it.
}

@Override
public void setMethod(Method method) {
    this.method = method;
}

}

Terminal

public class Terminal {

public HashMap<Character, InvokesMethodItf> commands;

public Terminal() {
    this.commands = new HashMap<Character, InvokesMethodItf>();


}


private void setCommand(char letter, Method method) {

    InvokesMethodItf inv = new InvokesMethod();

    inv.setMethod(method);

    this.commands.put(letter, inv);
}

public void executeCommand(char letter, String data) throws Exception {
    this.commands.get(letter).invokeMethod(data);    //pass data to invoke method
 }
}

Main

    public class Main {           

    Terminal commandLine = new Terminal();
    commandLine.setCommand('h',test());   //This should give syntax error or i am not sure
    commandLine.executeCommand('h', "This is a test");

   public Method test(String data){
        Log.d("Test", data);

        return null;
    }
}

UPDATE: I am trying to set multiple methods using setCommand and execute it.

commandline.setCommand('p',this.getClass().getDeclaredMethod("parseData",String.class,Integer.class), this);
commandline.setCommand('p', this.getClass().getDeclaredMethod("test"), this);

Then , calling

commandline.executeCommand('p', "test", 2345);

Only test function is calling.(Last setCommand function is running). I think it is overwriting Method . Isn't there is someway to pass multiple methods in setCommand function. Changing type of Method to Method[] is not working either.

4
  • When invoking a method, you also need to pass the instance holding the method you want to invoke: method.invoke(instance, params). See the API. Commented Sep 29, 2014 at 9:08
  • For static method use null as instance Commented Sep 29, 2014 at 9:11
  • @talex test is not a static method Commented Sep 29, 2014 at 9:19
  • @sp00m can you give more insight about the implementation? Commented Sep 29, 2014 at 10:13

2 Answers 2

1

When invoking a method, you need to pass the instance from which the method should be invoked as well as the parameters:

public interface MethodInvoker {

    // the method + the instance from which the method should be called
    public void setMethod(Method method, Object instance);

    // invokes the method
    public void invoke(Object... params) throws Exception;

}

Here an implementation:

public class MethodInvokerImpl implements MethodInvoker {

    private Method method;
    private Object instance;

    @Override
    public void setMethod(Method method, Object instance) {
        this.method = method;
        this.instance = instance;
    }

    @Override
    public void invoke(Object... params) throws Exception {
        // first param: instance, then the parameters
        method.invoke(instance, params);
    }

}

Then your Terminal:

public class Terminal {

    public Map<Character, MethodInvoker> commands;

    public Terminal() {
        commands = new HashMap<Character, MethodInvoker>();
    }

    // instance needed, since MethodInvoker#setMethod needs it
    public void addCommand(char letter, Method method, Object instance) {
        MethodInvoker invoker = new MethodInvokerImpl();
        invoker.setMethod(method, instance);
        commands.put(letter, invoker);
    }

    public void executeCommand(char letter, Object... params) throws Exception {
        commands.get(letter).invoke(params);
    }

}

Finally in your main:

public void test(String data) {
    System.out.println(data);
}

public void main() throws Exception {
    Terminal commandLine = new Terminal();
    // #text() will be called from "this" instance
    commandLine.addCommand('h', getClass().getMethod("test", String.class), this);
    commandLine.executeCommand('h', "This is a test");
}

Note that static methods don't need instances since they belong to the class, e.g.:

public void main() throws Exception {
    Terminal commandLine = new Terminal();
    // simply pass "null" as instance
    commandLine.addCommand('h', getClass().getMethod("test", String.class), null);
    commandLine.executeCommand('h', "This is a test");
}

public static void test(String data) {
    System.out.println(data);
}

See https://stackoverflow.com/a/542122/1225328 and https://stackoverflow.com/a/1348228/1225328 as well.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanx , i have one small doubt in getClass().getMethod("test", String.class) . Suppose , in my main activity i declare the test function normally . If i use getClass().getMethod("test", String.class) in some other scope,lets say i created the interface and use addCommand in that override function. It is catching this error java.lang.NoSuchMethodException: test [class java.lang.String]
i did some debugging turns out getClass().getMethod("test", String.class) .checks the function in same scope(not global).
@Neil getClass() returns the class of this. In my example, if main() is in class MyMain for example, getClass() will equal MyMain.class (unless it has been instantiated via a subclass). That is to say, if you want to call the method AnyClass#anyMethod(String, Integer), then use AnyClass.class.getMethod("anymethod", String.class, Integer.class).
0

Method is an Object which you will have to get using reflection.As I see the problems in your code,you cannot get Method Object using method invocation.Change this in your Main class.Check the javadoc here for getting Method Object from Class Object(for class Object you can use Class.forName(String class_binary_name) or Class literal

   public class Main {           

        Terminal commandLine = new Terminal();
        Method method = Main.class.getMethod("test",String.class);
        commandLine.setMethod('h',method); 
        commandLine.executeCommand('h', "This is a test");

        public void test(String data){
            Log.d("Test", data);

        }
    }

Also,change the return type of test class to void if you are not planning to return anything

1 Comment

I tried the same code. Nothing is getting print in log. App is running fine. 09-29 15:10:18.873: W/System.err(1818): java.lang.IllegalArgumentException: expected receiver of type com.example.hello.MainActivity, but got java.lang.String 09-29 15:10:18.883: W/System.err(1818): at java.lang.reflect.Method.invokeNative(Native Method) 09-29 15:10:18.903: W/System.err(1818): at java.lang.reflect.Method.invoke(Method.java:511) Getting these system errors. I think problem is in method.invoke() function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.