mardi 27 avril 2021

How to implement interface with reflection and pass it to a method called with reflection in Java?

I need to implement a listener and pass it to a service. I do not have a direct access to both interface and service classes.

I am stuck at passing Proxy interface to a method via reflection.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {

        try {
            Class<?> c = Class.forName("android.view.WindowManagerGlobal");
            Method m = c.getMethod("getWindowManagerService");
            Object windowManager = m.invoke(c.newInstance(), new Object[] {});

            Class<?> someInterface = Class.forName("android.view.WindowManagerService$WindowChangeListener");

            Object instance = createListenerInstance(someInterface);
            instance.getClass().getDeclaredMethod("windowsChanged", (Class<?>[]) null).invoke(instance, new Object[] {});
            System.out.println(instance.getClass().getName());

            // Fails with:
            // java.lang.NoSuchMethodException: android.view.WindowManagerService.addWindowChangeListener(com.sun.proxy.$Proxy0)
            windowManager.getClass().getMethod("addWindowChangeListener", instance.getClass()).invoke(windowManager, new Object[] { instance });

            System.out.println(windowManager.getClass().getName());
        } catch (Exception e) {
            System.out.println(e.getCause());
        }
    }

    private static Object createListenerInstance(Class<?> someInterface) {
        return Proxy.newProxyInstance(someInterface.getClassLoader(), new Class<?>[] { someInterface }, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                // Handle the invocations
                if (method.getName().equals("windowsChanged")) {
                    System.out.println("windowsChanged");
                } else if (method.getName().equals("focusChanged")) {
                    System.out.println("focusChanged");
                }
                return args;
            }
        });
    }
}

The following is the piece of code I have no access to by either new operator or ClassName.class:

package android.view;

public class WindowManagerService {

    public interface WindowChangeListener {
        public void windowsChanged();
        public void focusChanged();
    }
    public void addWindowChangeListener(WindowChangeListener listener) {
        System.out.println("Listener added: " + listener);
    }
    public void removeWindowChangeListener(WindowChangeListener listener) {
        System.out.println("Listener removed: " + listener);
    }
}

/////////
package android.view;

public class WindowManagerGlobal {
    private WindowManagerService windowManagerService = new WindowManagerService();

    public WindowManagerService getWindowManagerService() {
        return windowManagerService;
    }

    public void setWindowManagerService(WindowManagerService windowManagerService) {
        this.windowManagerService = windowManagerService;
    }
}

I do not know how to pass the proxy object to a method that requires WindowChangeListener.





Aucun commentaire:

Enregistrer un commentaire