15

I'm working on some dynamic invocation of code via an interpreter, and I'm getting into the sticky ugly areas of method resolution as discussed in JLS section 15.12.

The "easy" way to choose a method is when you know the exact types of all the arguments, at which point you can use Class.getDeclaredMethod(String name, Class[] parameterTypes). Maybe you have to check method accessibility and the class's superclasses/superinterfaces.

But this doesn't cover any of the following cases, so it's kind of useless:

  • boxing/unboxing primitives
  • subtypes
  • varargs
  • a null argument (which can be any type, unless the interpreter knows otherwise; at compile-time any ambiguity would be eliminating by casting null to a class/interface)
  • primitive type conversion (not part of Java, but allowable in the context of languages -- e.g. Rhino Javascript where all numbers are floating-point, so the Java code might take an int but the caller passes in a number which is either an int or a double)

(see below for a quick example of the first three)

So now I have to write my own method resolution library...

Is there any well-known framework library to assist in this?

package com.example.test.reflect;

import java.lang.reflect.Method;

public class MethodResolutionTest {
    public void compute(int i)              { /* implementation... */ }
    public void compute(Long l)             { /* implementation... */ }
    public void compute(Object obj)         { /* implementation... */ }
    public void compute(String... strings)  { /* implementation... */ }

    public static void main(String[] args) {
        Class<?> cl = MethodResolutionTest.class;

        /* these succeed */
        findAndPrintMethod(cl, "compute", int.class);
        findAndPrintMethod(cl, "compute", Long.class);
        findAndPrintMethod(cl, "compute", Object.class);
        findAndPrintMethod(cl, "compute", String[].class);

        /* these fail */
        findAndPrintMethod(cl, "compute", Integer.class);
        findAndPrintMethod(cl, "compute", long.class);
        findAndPrintMethod(cl, "compute", MethodResolutionTest.class);
        findAndPrintMethod(cl, "compute", String.class, String.class);
    }
    private static void findAndPrintMethod(Class<?> objectClass, 
            String methodName, Class<?>... parameterTypes) 
    {
        try {
            Method method = findMethod(objectClass, methodName, 
                   parameterTypes);
            System.out.println(method.toString());
        }
        catch (SecurityException e) {
            e.printStackTrace();
        }
        catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    private static Method findMethod(Class<?> objectClass, 
            String methodName, Class<?>[] parameterTypes) 
        throws SecurityException, NoSuchMethodException 
    {
        return objectClass.getDeclaredMethod(methodName, parameterTypes);
    }
}
reevesy
  • 3,452
  • 1
  • 26
  • 23
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • 1
    [This answer handles some of your cases like subtypes](http://stackoverflow.com/questions/2580665/java-getmethod-with-superclass-parameters-in-method/2580699#2580699). – Jonathon Faust May 16 '11 at 18:05
  • 1
    @Jonathon: I know about isAssignableFrom. I got something homegrown working with subtypes and boxing/unboxing. Then I started into varargs and it got nasty, and I thought, "Wait a minute, why am I doing this at all?" so I'm specifically looking for a pre-existing library. (Or at least a good set of pre-existing test cases) Otherwise I can do this on my own, but it's a big pain. – Jason S May 16 '11 at 18:41
  • 1
    Unless you find a sweet library, I think whatever you do is going to be ugly and hard to read. – Jonathon Faust May 16 '11 at 19:23
  • Yeah, I know. How does one entice the Java demigods at Google or Oracle or IBM or Apache or whatever to make a good non-viral open-source library to do this? It's a missing chunk of Java reflection, IMHO. I can come up with something that works for my own purposes, but I think it would be far from perfect, in either correctness / documentation / maintainability. – Jason S May 16 '11 at 19:27

4 Answers4

3

You may want to read this blog post and check out ClassMate. It should do most of the grungy work for you.

Holger Hoffstätte
  • 1,918
  • 1
  • 13
  • 10
  • ARGH! So promising, but it's slightly different -- it resolves generic types, but doesn't do anything for method resolution. But at least it's a start, and I bet I could cajole the authors into extending it. – Jason S May 17 '11 at 14:13
2

Commons beanutils have this function for finding matching methods: getMatchingAccessibleMethod

It works with primitive types but it is somewhat indeterministic as the docs says.

jontro
  • 10,241
  • 6
  • 46
  • 71
  • 1
    Note that in `getMatchingAccessibleMethod` the primitive matching is one way - parameter `Long.class` will match `foo(long)` but `Long.TYPE` won't match `foo(Long)` – McDowell May 16 '11 at 23:13
  • +1: @Bengt: what a relief to find out Apache's got some tools, maybe not what I wanted, but something at least. – Jason S May 16 '11 at 23:47
0

One of the users on guava-discuss recommended I look at the Mirror library.

Unfortunately it doesn't handle overloading resolution either, at least not at present.

Jason S
  • 184,598
  • 164
  • 608
  • 970
-1

I've had some success with MVEL and properties, but I can't recall whether it can dispatch method calls.

However, you might be looking for different language entirely. Given the nature of the problem, I suggest taking a look at Groovy, which integrates very cleanly with Java.

  • hmm, I'm "stuck" with Java for various reasons, the biggest one being maintainability (adding a different language significantly constrains my ability to get help from other developers) – Jason S May 16 '11 at 23:38