Background: In several Java frameworks like Spring there is the possibility to have methods that are called with injected parameter values. A good example is a controller action in Spring Web/MVC that receives a POST value and has a redirect attribute.
Example:
@RequestMapping(value = "/testform", method = RequestMethod.POST)
public ModelAndView testform(@RequestParam(value = "postvalue") String postvalue, RedirectAttributes attributes)
{
if(postvalue.equals("Test"))
{
// Do stuff with attributes
}
return new ModelAndView("addresses");
}
For example when I would like to use something similar in an own application (No Spring included available) - I end up with something like that (Hacked together):
Strign actionname = "mymethod";
Controller controller = new SampleController();
for(Method method : controller.getClass().getDeclaredMethods())
{
String name = method.getName();
if(name.equals(actionname))
{
int parametercount = method.getParameterCount();
if(parametercount == 0) // No parameter
{
ModelAndView view = (ModelAndView) method.invoke(controller);
// Do stuff
}
else if(parametercount == 1) // 1 String parameter
{
ModelAndView view = (ModelAndView) method.invoke(controller, new String("parameter1"));
// Do stuff
}
else if(parametercount == 2) // 2 String parameters
{
ModelAndView view = (ModelAndView) method.invoke(controller, new String("parameter1"), new String("parameter2"));
// Do stuff
}
else // Error
{
// Unsupported method
}
break;
}
}
Problem: This solution only supports void, 1-parameter and 2-parameter methods that take a string as argument - nothing else
Question: How does Java and Spring allow such a feature? Does Spring have a huge array of method.invoke(...) that are suitable for the most common methods or is there a more dynamic solution to this problem?
Final solution: I ended up with this (unfinished) solution based on Seelenvirtuose answer:
else if(parametercount == 2)
{
Object[] parameters = new Object[2];
parameters[0] = new String("Hello");
parameters[1] = new String("world!");
method.invoke(controller, parameters);
}
Aside from any injection dependency frameworks in general (and Spring specifically), you seem to ask how to reflectively call methods with an arbitrary number of parameters.
As you can see in the invoke method's signature, you provide all parameters in an array. So you simply should assemble an argument array and provide that:
Object[] arguments = createArguments(parametercount); // create array of correct size
(ModelAndView) method.invoke(controller, arguments);
Note, that varargs are treated like an arry. Oh, and please respect the comments about string behaviors.
In principle Spring does the same thing, just more sophisticated.
Especially they don't look for names (at least for many things) but for annotations. You can get the annotations of classes, methods, fields and so on.
The other thing they'll use is that invoke takes an vararg, which is basically an array, so instead of having one if branch for each number of parameters, they pass just an array with the correct number of elements.
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