How to get 'proxied' object from an existing dynamic proxy

Marco R. :

Is there an some API like Proxy.getProxiedObject(), that will return the original object of a dynamic proxy? I would like, for example, to invoke equals on the proxied objects, rather than on the dynamic proxies themselves, like in the following example:

public class ProxyTest implements InvocationHandler {

    public static Object createProxy(Object target) {
        Class<? extends Object> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new ProxyTest());      
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        // PROXIED OBJECTS COMPARISON - DESIRED
//      return Proxy.getProxiedObject(proxy).equals(Proxy.getProxiedObject(args[0]));

        // DYNAMIC PROXIES COMPARISON - UNDESIRED
//      return proxy.equals(args[0]);

        return null;
    }

    public static void main(String[] args) {
        Object proxied = createProxy(new Object());
        System.out.println(proxied.equals(proxied));
    }
}
Marco R. :

I don't think there's any API available for this; but I built a workaround this using the API that retrieves the InvocationHandler from any Proxy object, and the one that tests where or not a Class is a Proxy class:

Using these I created an abstract extension of InvocationHandler to keep a reference to the object being proxied, with a static utility to retrieve the proxied object out of any potential Proxy object, and a factory utility for creating Proxys using the target object:

    public abstract class ProxiedSavedInvocationHandler implements InvocationHandler {
        public static Object getProxied(Object proxy) {
            if (!Proxy.isProxyClass(proxy.getClass())) 
                return null;

            InvocationHandler handler = Proxy.getInvocationHandler(proxy);
            return (handler instanceof ProxiedSavedInvocationHandler) ? 
                    ((ProxiedSavedInvocationHandler)handler).proxied : null;
        }

        protected final Object proxied;

        public ProxiedSavedInvocationHandler(Object proxied) { 
            this.proxied = proxied; 
        }

        public Object getProxied() {
            return proxied;
        }

        public Object createProxy() {
            Class<? extends Object> clazz = proxied.getClass();
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }
    }

Then I just used the newly created class like this:

        class MyProxiedSavedInvocationHandler extends ProxiedSavedInvocationHandler {
        ...
        }

        ProxiedSavedInvocationHandler handler = new MyProxiedSavedInvocationHandler(target); 
        Object proxy = handler.createProxy();

        // DESIRED API THROUGH STATIC UTILIY
        Object proxied1 = ProxiedSavedInvocationHandler.getProxied(proxy);

        // DESIRED API THROUGH INSTANCE UTILIY
        Object proxied2 = handler.getProxied();

The only dependency on this solution is having the ProxiedSavedInvocationHandler utility class where all the logic and new APIs are located. This class can be extended even to include APIs to delegate behavior to other InvocationHandlers transparently; but the minimum required is there.

The following is a full working example application of this solution:


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

public class ProxyTest {

    static class MyProxiedSavedInvocationHandler extends ProxiedSavedInvocationHandler {
        public MyProxiedSavedInvocationHandler(Object proxied) {
            super(proxied);
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
            if (!method.getName().equals("equals"))
                return method.invoke(proxied, args);

            Object other = ProxiedSavedInvocationHandler.getProxied(args[0]);
            System.out.println("====");
            System.out.println("\tRunning 'equals' inside proxy with:");
            System.out.println("\tthis: " + proxied);
            System.out.println("\tother: " + other);
            System.out.println("====");
            return proxied.equals(other);
        }
    }

    static abstract class ProxiedSavedInvocationHandler implements InvocationHandler {
        public static Object getProxied(Object proxy) {
            if (!Proxy.isProxyClass(proxy.getClass())) 
                return null;

            InvocationHandler handler = Proxy.getInvocationHandler(proxy);
            return (handler instanceof ProxiedSavedInvocationHandler) ? 
                    ((ProxiedSavedInvocationHandler)handler).proxied : null;
        }

        protected final Object proxied;

        public ProxiedSavedInvocationHandler(Object proxied) { 
            this.proxied = proxied; 
        }

        public Object getProxied() {
            return proxied;
        }

        public Object createProxy() {
            Class<? extends Object> clazz = proxied.getClass();
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        }
    }

    // TO TEST EDGE SCENARIONS
    private static Object createProxy(Class<? extends Object> clazz, InvocationHandler handler) {
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), handler);
    }

    // MAIN
    public static void main(String[] args) {
        // EDGE SCENARIOS
        Object proxiedFromNotEnhancedProxy = 
                ProxiedSavedInvocationHandler.getProxied(createProxy(Object.class, (p, m, a) -> null));
        Object proxiedFromNotAProxy = 
                ProxiedSavedInvocationHandler.getProxied(new Object());
        System.out.println("proxied from NOT ENHANCED PROXY: " + proxiedFromNotEnhancedProxy);
        System.out.println("proxied from NOT A PROXY: " + proxiedFromNotAProxy);
        System.out.println();

        // FUNCTIONALITY DESIRED
        Object target = new Object();
        ProxiedSavedInvocationHandler handler = new MyProxiedSavedInvocationHandler(target); 

        Object proxy = handler.createProxy();
        Object proxied1 = ProxiedSavedInvocationHandler.getProxied(proxy);
        Object proxied2 = handler.getProxied();

        System.out.println("target: " + target);
        System.out.println("proxied1: " + proxied1);
        System.out.println("target == proxied1: " + (target == proxied1));
        System.out.println("proxy.equals(proxy): " + proxy.equals(proxy));
    }
}

Complete code on GitHub

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=135335&siteId=1