views:

54

answers:

2

First off let me say I am maintaining someone else's poorly designed code so I am limited in how much I can change it.

Now what is happening is that they have created a series of methods that are invoked by reflection. One of those methods takes a Map as one of its arguments. At runtime this Map is implemented with a Hashtable.

Here's the problem - I get a NoSuchMethodException because it is looking for a method with Hashtable as an argument even though a Hashtable implements the Map interface. What is confusing me is that if I don't use reflection (a major design change in this case) and passed a Hashtable it would invoke the method with the Map parameter - so why doesn't it work the same way when I use reflection?

Given that I pretty much have to stick with reflection is there any way to get the method with the Map argument to get invoked when I pass it a class that implements that interface?

If you want I can mock some code up to demonstrate...

A: 

I had a similar problem. I see 2 solutions:

solution 1: you can develop a more complicated search method.

Example of an algorithm you could use :

You search with the parameter type. If the search fails (Exception), but one of the parameters has a super type (or implements an interface), you search the same method name, but with this superclass (or interface). You throw the exception only if no method is found after this search algorithm.

Note : if your methods have several parameters, be sure to verify with each possible combination of supertypes/interfaces. It can result in a quite complex search algorithm...

solution 2: another method, much easier, is to precise the types separately from the parameters. This method more verbose can be necessary if you want to use null parameters.

So, "invokeMethod(String methodName, Object[] paramters)" becomes "invokeMethod(String methodName, Class[] methodParamTypes, Object[] parameters)".

Benoit Courtine
+1  A: 

If you are using getMethod(String name, Class[] parameterTypes) from java.lang.Class, you need to specify parameter types as expressed in the method signature of the interface (static type), not the type of the object at run-time (dynamic type).

So, for methodXyz(Map map), instead of:

Method m = cl.getMethod("methodXyz", new Class[]{argument.getClass()});

do this:

Method m = cl.getMethod("methodXyz", new Class[]{Map.class});
gawi
Problem is there are about 20 methods called methodXyz with various arguments that work just fine. It is only this new one that takes a Map as an argument that is causing problems.I can do what you say but that requires that I determine if the parameter in question is a Map first using instanceof for instance :)I don't understand why reflection does not operate the same way as non-reflected code when looking up methods?!?! It must use an entirely different mechanism I guess...
BigMac66
The getMethod() expects the exact types of the definition. That's why it's named getMethod() rather than findMethod(). You can code your own findMethod() if you are doing dynamic method dispatch often. This would involve looking for methods have the proprer name, filtering the one where parameters are not compatbile with the given arguments and deals with cases where more than a single method remain candidate, e.g. the following case is ambiguous and is a compilation error: new StringBuffer().append(null).
gawi