2

I would like to call method(using reflection) which has parameter Interface - i.e: List but with implementation of List. For example:

public class Test {

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test1.class.getMethod("method", new Class[]{ArrayList.class});

    }

    public class Test1 {

        public void method(List list) {
            System.out.println("method");
        }
    }
}

I get NoSuchMethodException. In this case i know which params i get, problem is that I want to use this in general when i don't "statically" know param types.

Is possible that getMethod returns also method which has interface as parameter? Or i have to write my own "methodsearcher"

Thank you.

EDIT: It's much more complicated. I'm trying to write something like "dynamic modular architecture" in my program. I have Core, which should comunicate with other modules. So i don't know params classes in programming time but in runtime.

 public Object processMessage(String target, String methodName, List<Object> params, Object returnNonExist) {
    Module m = modules.get(target);
    if (m == null) {
        return returnNonExist;
    } else {
        Class[] paramsTypes = new Class[params.size()];
        for (int i = 0; i < params.size(); i++) {
            paramsTypes[i] = params.get(i).getClass();
            }
        }
        try {
            Method method = m.getClass().getMethod(methodName, paramsTypes);
            Object result = method.invoke(m, params.toArray());
            return result;
        }

Is it better?

2
  • 2
    why do you want to do that? There is no method in Test 1 that takes ArrayList as argument and so you dont get one. Commented Oct 11, 2013 at 8:13
  • 1
    Possible duplicate: stackoverflow.com/questions/2580665/… Commented Oct 11, 2013 at 8:16

3 Answers 3

4

I probably found solution - I have to write my own "method searcher" which respect interface implementation and superclases. It looks like this:

public static Method findMethod(Object m, String methodName, Class[] paramsTypes) {
    Method[] metody = m.getClass().getDeclaredMethods();
    List<Method> sameNames = new ArrayList<Method>();
    // filter other names
    for (Method meth : metody) {
        if (meth.getName().equals(methodName)) {
            sameNames.add(meth);
        }
    }
    // lets find best candidate
    if (sameNames.isEmpty()) {
        return null;
    } else {
        // filter other count of parameters
        List<Method> sameCountOfParameters = new ArrayList<Method>();
        for (Method meth : sameNames) {
            if (meth.getParameterTypes().length == paramsTypes.length) {
                sameCountOfParameters.add(meth);
            }
        }
        if (sameCountOfParameters.isEmpty()) {
            return null;
        } else {
            for (Method meth : sameCountOfParameters) {
                // first one, which is suitable is the best
                Class<?>[] params = meth.getParameterTypes();
                boolean good = true;
                for (int i = 0; i < params.length && good; i++) {
                    if (params[i].isInterface() && Arrays.asList(paramsTypes[i].getInterfaces()).contains(params[i])) {
                        //if i-th paramater type is Interface and we search method with its implementation
                        good = true;
                        continue;
                    } else {
                        // if we call it with subclass and parameter typ is superclass
                        if (paramsTypes[i].getSuperclass().equals(params[i])) {
                            good = true;
                            continue;
                        }
                    }
                    good = false;
                }
                if (good) {
                    return meth;
                }
            }
        }
    }
    return null;
}

I'am using this after standard getMethod throws "NoSuchMethodException" (It is in about 5% cases, so i don't care about speed.

Sign up to request clarification or add additional context in comments.

Comments

1

You should use List class, not ArrayList.

Method method = Test1.class.getMethod("method", new Class[]{List.class});

Comments

1

Great answer from @radeczek. I extended it to work on subclasses ...

    public Method findMethod(String name, Class<?>[] paramsTypes) {
        
        Method[] methods = object.getClass().getMethods();
        
        List<Method> sameNames = new ArrayList<Method>();
        
        // filter other names
        for (Method m : methods) {
            if (m.getName().equals(name)) {
                sameNames.add(m);
            }
        }
        
        // lets find best candidate
        if (sameNames.isEmpty()) {
            return null;
            
        } else {
            
            // filter other count of parameters
            List<Method> sameCountOfParameters = new ArrayList<Method>();
            for (Method m : sameNames) {
                
                if (m.getParameterTypes().length == paramsTypes.length) {
                    sameCountOfParameters.add(m);
                }
            }
            
            if (sameCountOfParameters.isEmpty()) {
                return null;
                
                
            } else {
                for (Method m : sameCountOfParameters) {
                    
                    // first one, which is suitable is the best
                    Class<?>[] params = m.getParameterTypes();
                    
                    boolean good = true;
                    
                    for (int i = 0; i < params.length && good; i++) {
                        
                        // Recurse into subclasses 
                        good = findSubclass(paramsTypes[i],params[i]);
                    }
                    if (good) {
                        return m;
                    }
                }
            }
        }
        return null;
    }
    
    /**
     * Recursive check for interfaces of superclasses. 
     * 
     * @param paramType
     * @param param
     * @return
     */
    private boolean findSubclass(Class<?> paramType, Class<?> param) {
        
        if (param.isInterface() && Arrays.asList(paramType.getInterfaces()).contains(param)) {
            return true;
        } else {
            
            if (paramType.getSuperclass() != null) {
                return findSubclass(paramType.getSuperclass(), param);
            } else {
                return false;
            }
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.