Soundariyaa Jakanadhan
Soundariyaa Jakanadhan

Reputation: 105

How to call method of method at runtime?

I know using reflection we can call method at run time. I have one requirement obj.getMethod1().getMethod2().getMethod3() to be called at run time. Method Name will be know only during run time. Number of methods also differ during run time. sometimes it can be obj.getMethod1().getMethod2().

Currently I am handling through array as below

 obj=initialObj;
 for(i=0;i<arrayValue.length;i++){
     tempobj=obj.getClass.getMethod(arrayValue[i])// arrayValue contains method name
     obj=tempobj;
 }

Is there any other better way of doing this?

Upvotes: 1

Views: 1397

Answers (2)

Oleg Cherednik
Oleg Cherednik

Reputation: 18245

This is util class, that contains common methods:

public final class ReflectionUtils {
    public static <T> T invokeMethod(Object obj, String name, Class<?>[] types, Object... values) throws Throwable {
        try {
            Method method = getMethod(obj.getClass(), name, types);
            method.setAccessible(true);
            return (T)method.invoke(obj, values);
        } catch(InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    private static Method getMethod(Class<?> cls, String name, Class<?>... types) throws NoSuchMethodException {
        Method method = null;

        while (method == null && cls != null) {
            try {
                method = cls.getDeclaredMethod(name, types);
            } catch(NoSuchMethodException ignored) {
                cls = cls.getSuperclass();
            }
        }

        if (method == null) {
            throw new NoSuchMethodException();
        }

        return method;
    }
}

This is how to call obj.getMethod1().getMethod2().getMethod3():

public static Object invokeMethods(Object obj, String... methodNames) throws Throwable {
    for (String methodName : methodNames)
        obj = ReflectionUtils.invokeMethod(obj, methodName, null);
    return obj;
}

And client code could look like this:

Object res = invokeMethods(obj, "getMethod1", "getMethod2", "getMethod2");

Upvotes: 0

Sweeper
Sweeper

Reputation: 271175

Assuming your methods don't have parameters, you can do this:

public static Object callChainedMethods(Object obj, String[] methodNames) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Class<?> type = obj.getClass();
    Object objectOnWhichToCallMethod = obj;
    for (String methodName : methodNames) {
        Method m = type.getMethod(methodName);
        objectOnWhichToCallMethod = m.invoke(objectOnWhichToCallMethod);
        type = objectOnWhichToCallMethod.getClass();
    }
    return objectOnWhichToCallMethod;
}

If you don't need to return the final return value:

public static void callChainedMethods(Object obj, String[] methodNames) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Class<?> type = obj.getClass();
    Object objectOnWhichToCallMethod = obj;
    for (String methodName : methodNames) {
        Method m = type.getMethod(methodName);
        objectOnWhichToCallMethod = m.invoke(objectOnWhichToCallMethod);
        type = objectOnWhichToCallMethod.getClass();
    }
}

For example:

String[] methods = {"toString", "getClass", "getClass"};
System.out.println(callChainedMethods((Integer)10, methods));
// prints "class java.lang.Class"
// because it is calling ((Integer)10).toString().getClass().getClass()

Upvotes: 1

Related Questions