0

I am trying to code a method 'interaction' which takes a keyboard input and calls the respective function. However, I am getting NoSuchMethodExceptions even when the input is valid.

public class Battle {
  public void interaction (String input, int x, int y, int z, Unit target) {
    Mechanic mch = new Mechanic();
    try {
      Method method = mch.getClass().getMethod(input, empty.getClass(), int.class, int.class, int.class, target.getClass());
      method.invoke(mch, empty,x, y, z, target);
  
    } catch (Exception ex) {
      System.out.print(ex.getClass().toString());
    }
  }

  private Dice[] empty = {};
}

public class Mechanic {
  public void fight (Dice[] dices, int x, int y, int z, Unit target) {
    int a = 0; // Some method involving dices in the actual code.
    Unit.setHp(x - y - z - a);
  }

  public void buff (int x, int y, int z, Unit target) {
    int a = 0; // Some method involving dices in the actual code.
    Unit.setAttack(x + y + z + a);
  }

// A class called Dice.
}

I do not understand why getMethod() is unable to find the methods 'fight' or 'buff' from class Mechanic.

I expect to be able to call the methods via a string input (and the corresponding arguments, but it just does not work. What am I doing wrong?

  • 2
    You need to show us the error. And why you're certain that that method exists. As a rule, when Java tells you the method does not exist, the method does not exist. Your protests to the contrary are, by definition, wrong since if the JVM cannot find it, the method doesn't exist. – justhecuke Jun 18 '23 at 04:23

1 Answers1

0

As a general rule, you should avoid doing what you're doing. Runtime reflection is a minefield of bugs waiting to happen. Don't do this to yourself. Find a way to implement this behavior with proper OOP design.

I don't have enough information to say for sure, but the type parameters you used are a red flag to me.

getMethod(input, empty.getClass(), int.class, int.class, int.class, target.getClass())

Using the class of instances is dangerous since getMethod looks for an exact type match. For if empty or target are subclasses of the types in your actual method parameter list, you're not going to find the method you want. You should try, as much as possible, to explicitly provide the exact class of your parameter list. Something like:

getMethod(input, MyEmptyClass.class, int.class, int.class, int.class, MyTargetClass.class)
justhecuke
  • 765
  • 4
  • 8
  • Thanks. target was indeed a subclass and your suggestion fixed it. Do you have any suggestions on fixing the code structure? I considered using switch blocks, but I'm worried I will introduce too many variations of methods in Mechanic (at the moment, there are at least 7 of them), and I'll just keep extending the switch block for a long time. – 2naKyrielight Jun 18 '23 at 05:48
  • @AnthonyTeh I don't know the context of what is going on so I can't tell you specifically how I would go about refactoring things. It's also subjective how to go about making it "better". That being said, I have to wonder why use strings at all and not just call the methods? Why the indirection here? What drove you to use reflection in the first place? Certainly there was a problem that this solved... and that problem is what needs a bit of creative thinking to work around. – justhecuke Jun 18 '23 at 19:51