tgkprog
tgkprog

Reputation: 4598

comparing method parameter types , filtering methods of a class that are of a certain signature

Want to group methods that match a signature. So given Class clz, return type class R and a list if parameter types Class []argsCLasses, fill up a map with matching methods from clz. I will be storing these methods in a map, and will that map to invoke the method with user supplied arguments.

With this map I do not need a big case statement, just get the Method by matching name, then invoke it.

Example,

class Foo {

    public void method(String a, String b, int i) {

    }

    public void method2(String a2, String b2, int i2) {

    }

    public void method3(String a2, int i2) {

    }

    public void method4(String a2, String b2, int i2) {

    }

}

If i want to match [String, String, Integer], method 1, 2 and 4 are matches.

What I have :

import org.apache.log4j.Logger;

public class ReflectUtils { private static final Logger logger = Logger.getLogger(ReflectUtils.class);

public static String fillMethods(Class clz, Class[] argsCLasses, Map<String, Method> methods) {
    String rtn = null;
    synchronized (methods) {

        synchronized (clz) {
            try {
                Method[] methodsAvail = clz.getMethods();
                boolean match = false;
                for (Method mtd : methodsAvail) {
                    Class rtnM = mtd.getReturnType();
                    // if (rtnM.isAssignableFrom( rtnType)) {
                    // continue;
                    // }
                    Class[] args = mtd.getParameterTypes();
                    if (argsCLasses.length != args.length) {
                        continue;
                    }
                    match = true;
                    for (int i = 0; i < argsCLasses.length; i++) {
                        if (args[i] != argsCLasses[i]) {
                            match = false;
                        }
                    }
                    if(match){
                        methods.put(mtd.getName(), mtd);
                    }
                }
            } catch (Throwable e) {
                rtn = "ERROR :" + e;
                logger.error("Err fill methods :" + e, e);

            }
        }
    }
    return rtn;
}

public static void main(String[] args) {
    Class[] argsCLasses = new Class[] { String.class, String.class, Integer.class };
    Map<String, Method> methods = new HashMap<String, Method>();
    // Class clz, Class[] argsCLasses, Map<String, Method> methods
    fillMethods(Foo.class, argsCLasses, methods);
    System.out.println(methods);
    System.out.println();
    System.out.println(methods.keySet());
}

}

Is there already something to this?

In the inner loop

if (args[i] != argsCLasses[i]) 

Should I be using isAssignableFrom ? Or something else to see if its a matching arg? Anything else to be compared to see if method meets criteria?

Upvotes: 0

Views: 337

Answers (2)

Andrey Chaschev
Andrey Chaschev

Reputation: 16496

You could use isAssignableFrom to match arguments. You might also need to match primitives types to their wrappers. Example from my utility library:

private static boolean _matches(Class inputParam, Class<?> declaredArgumentParam) {
    boolean matches = true;
    if (!declaredParam.isAssignableFrom(inputParam)) {
        if(
            (inputParam.isPrimitive() && Primitives.wrap(inputParam) == declaredArgumentParam) ||
            (declaredArgumentParam.isPrimitive() && Primitives.wrap(declaredArgumentParam) == inputParam)
            ){
        }else{
            matches = false;
        }
    }
    return matches;
}

Complete source at github: HavingMethodSignature.java.

Upvotes: 1

bobbel
bobbel

Reputation: 3356

When a parameter doesn't fit the method signature, you are continuing to the inner loop. But you have to continue to the outer loop.

You can do this for example with a label:

outerLoop: // Label
for (Method mtd : methodsAvail) {
    Class rtnM = mtd.getReturnType();
    Class[] args = mtd.getParameterTypes();
    if (argsCLasses.length != args.length) {
        continue;
    }
    for (int i = 0; i < argsCLasses.length; i++) {
        if (args[i] != argsCLasses[i]) {
            continue outerLoop;  // continue to the label outerLoop
        }
    }
    methods.put(mtd.getName(), mtd);
}

Upvotes: 1

Related Questions