Thus, the getMethod solution will work when you have the exact parameter
types for whatever method it is you are trying to get at. However, if you
are simply looking for a 'compatible' method, it becomes more complicated.
You can simply call getMethods and start comparing the parameter types of
each returned method that has a matching name. If the class you want to pass
in is a subclass (this can be determined with isAssignableFrom) of the
parameter in question, you have a match. If all of the parameters are
matched in this fashin, the current method being tested is compatible.
Still, this is not a 100% correct solution. Perhaps the first method you
came across is compatible, but there is yet another, more specific,
overloaded method that would better match the parameter types you have.
Consider this example:
class A {}
class B extends A {}
class C extends B {}
public class MyClass {
public print(A a) { System.out.println("Houston, we have an 'A'."); }
public print(B b) { System.out.println("Houston, we have an 'B'."); }
public print(C c) { System.out.println("Houston, we have an 'C'."); }
public doPrint() {
C someClass = new C();
Method methods[] = this.getClass().getMethods();
for(int index = 0; index < methods.length; index ++) {
Method currentMethod = methods[index];
Class parameterTypes = currentMethod.getParameterTypes();
if(currentMethod.getName().equals("print") && parameterTypes.length == 1)
{
Class parameterType = parameterTypes[0];
if(parameterType.isAssignableFrom(someClass)) { // Is someClass a
subclass of the parameter type?
return currentMethod.invoke(this, someClass);
}
}
}
}
}
In this simplified example, which method is called depends on the order of
the methods in the array returned by the getMethods call. Any of the print
methods can handle a parameter of type class C because a class C is a class
B, and likewise, a class A.
The ideal solution would need to match Java's compile-time priorities ind
oing the same thing. Yet, I'm not sure of what those priorities are. Even if
I can get the priorities, actually coding the logic to determine this at
runtime looks like it would be quite involved.
Any ideas?
--
-----------------------------------------------------
Brian J. Sayatovic
mailto:tr...@1.net (replace '1' with 'one')
It may be a bit involved, but it shouldn't be impossible. I haven't done
any reflection stuff yet (apart from a quick test now just to follow your
example) but I don't see any reason for it to be impossible.
As for finding the logic: look at the JLS section 15.11.2.
I've got a bit of spare time now, so I'll see if I can come up with a bit
of code to do what you want.
--
Jon Skeet - sk...@pobox.com
http://www.pobox.com/~skeet/
Right. Well, I've had a go, and here's what I've come up with. Let me know if
you find any problems in it. It's my first try at reflection, so there may well
be a few. (isAssignableFrom somehow does my head in - I need to sit and stare at
it for about a minute each time to work out which way round to have the arguments.
Silly, I know.)
Hope it helps :)
import java.lang.reflect.Method;
import java.util.Vector;
public class FindMethod
{
/**
* Finds the most specific applicable method
*
* @param source Class to find method in
* @param name Name of method to find
* @param parameterTypes Parameter types to search for
*/
public static Method findMethod (Class source,
String name,
Class[] parameterTypes)
throws NoSuchMethodException
{
return internalFind (source.getMethods(),
name,
parameterTypes);
}
/**
* Finds the most specific applicable declared method
*
* @param source Class to find method in
* @param name Name of method to find
* @param parameterTypes Parameter types to search for
*/
public static Method findDeclaredMethod (Class source,
String name,
Class[] parameterTypes)
throws NoSuchMethodException
{
return internalFind (source.getDeclaredMethods(),
name,
parameterTypes);
}
/**
* Internal method to find the most specific applicable method
*/
private static Method internalFind (Method [] toTest,
String name,
Class[] parameterTypes)
throws NoSuchMethodException
{
int l = parameterTypes.length;
// First find the applicable methods
Vector applicableMethods = new Vector();
for (int i=0; i < toTest.length; i++)
{
// Check the name matches
if (!toTest[i].getName().equals (name))
continue;
// Check the parameters match
Class[] params = toTest[i].getParameterTypes();
if (params.length != l)
continue;
int j;
for (j=0; j < l; j++)
if (!params[j].isAssignableFrom (parameterTypes[j]))
break;
// If so, add it to the list
if (j==l)
applicableMethods.add (toTest[i]);
}
/*
* If we've got one or zero methods, we can finish
* the job now.
*/
int size = applicableMethods.size();
if (size==0)
throw new NoSuchMethodException ("No such method: "+name);
if (size==1)
return (Method) applicableMethods.elementAt (0);
/*
* Now find the most specific method. Do this in a very primitive
* way - check whether each method is maximally specific. If more
* than one method is maximally specific, we'll throw an exception.
* For a definition of maximally specific, see JLS section 15.11.2.2.
*
* I'm sure there are much quicker ways - and I could probably
* set the second loop to be from i+1 to size. I'd rather not though,
* until I'm sure...
*/
int maximallySpecific=-1; // Index of maximally specific method
for (int i=0; i < size; i++)
{
int j;
// In terms of the JLS, current is T
Method current = (Method)applicableMethods.elementAt (i);
Class[] currentParams = current.getParameterTypes();
Class currentDeclarer = current.getDeclaringClass();
for (j=0; j < size; j++)
{
if (i==j)
continue;
// In terms of the JLS, test is U
Method test = (Method)applicableMethods.elementAt (j);
Class[] testParams = test.getParameterTypes();
Class testDeclarer = test.getDeclaringClass();
// Check if T is a subclass of U, breaking if not
if (!testDeclarer.isAssignableFrom (currentDeclarer))
break;
// Check if each parameter in T is a subclass of the
// equivalent parameter in U
int k;
for (k=0; k < l; k++)
if (!testParams[k].isAssignableFrom (currentParams[k]))
break;
if (k != l)
break;
}
// Maximally specific!
if (j==size)
{
if (maximallySpecific != -1)
throw new NoSuchMethodException
("Ambiguous method search - more "+
"than one maximally specific method");
maximallySpecific=i;
}
}
if (maximallySpecific==-1)
throw new NoSuchMethodException ("No maximally specific method.");
return (Method) applicableMethods.elementAt (maximallySpecific);
--
-----------------------------------------------------
Brian J. Sayatovic
mailto:tr...@1.net (replace '1' with 'one')
Jon Skeet <sk...@pobox.com> wrote in message
news:MPG.136930225581cad798a17b@news...