I am trying to create a method invokeMethod(String methodName, Object...args) which invokes a method from a superclass on the current instance. I have tried the following implementation.
public void invokeMethod(String methodName, Object...args) {
//Array to hold the classes of the arguments
Class<?>[] classes = new Class<?>[args.length];
//Initialize each class in the array to the class of each argument
for(int i = 0; i < args.length; i++)
classes[i] = args[i].getClass();
try {
//find the method
Method m = this.getClass().getMethod(methodName, classes);
//invoke the method
m.invoke(this, args);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
The problem with this implementation is if I try to invoke a method with primitive parameters, I get a NoSuchMethodException because it is looking for a method with parameters whose type is the wrapper class equivalent.
For example, if I try to invoke a method with signature line(float, float, float, float) by trying invokeMethod("line", 50f, 50f, 50f, 50f), I get an exception similar to
java.lang.NoSuchMethodException: DynamicSketch.line(java.lang.Float, java.lang.Float, java.lang.Float, java.lang.Float)
at java.base/java.lang.Class.getMethod(Class.java:2109)
at DynamicSketch.invokeMethod(DynamicSketch.java:32)
at DynamicSketch.setup(DynamicSketch.java:19)
at processing.core.PApplet.handleDraw(PApplet.java:2412)
at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:316)
Is there anyway to make my invokeMethod method work with primitive arguments?
Edit: The solution here does not work because I do not know exactly what primitive types are in the signature when executing my method. I want to be able to execute methods like size(int, int) and line(float, float ,float ,float) using my method, and the solution in the link does not easily work with this. The only solution I see to this is define an if statement for every possible method in the superclass and then use the solution in the link, but I wanted a less tedious way.
When arguments such as 10 or 10.0f are passed into the method, they are automatically wrapped, because the parameter type is Object....
Therefore, you need to check for these wrapper types and unwrap them. Your for loop can look like this:
for(int i = 0; i < args.length; i++) {
if (args[i].getClass() == Integer.class) {
classes[i] = int.class;
} else if (args[i].getClass() == Float.class) {
classes[i] = float.class;
} else if (args[i].getClass() == Double.class) {
classes[i] = double.class;
} else {
classes[i] = args[i].getClass();
}
}
I have only added 3 cases here, you can add the other 5 yourself.
This means that you can't call methods with wrapper type arguments now. If you want to call those as well, you need to
Edit:
As Holger suggested in the comments, you can also let the JVM find a suitable method for you, by using
new Statement(this, methodName, args).execute();
Docs for the Statement class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With