Как получить «прокси» объект из существующего динамического прокси

Есть ли какой-нибудь API, такой как Proxy.getProxiedObject() , который будет возвращать исходный объект динамического прокси? Я хотел бы, например, вызывать equals на прокси-объектах, а не на самих динамических прокси, как в следующем примере:

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));
    }
}

Всего 1 ответ


Я не думаю, что для этого есть какой-либо API; но я создал обходной путь, используя API, который извлекает InvocationHandler из любого объекта Proxy , и тот, который проверяет, является ли Class Proxy или нет:

Используя их, я создал абстрактное расширение InvocationHandler для хранения ссылки на проксируемый объект, статическую утилиту для извлечения прокси- объекта из любого потенциального объекта Proxy и фабричную утилиту для создания Proxy с использованием целевого объекта:

    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);
        }
    }

Тогда я просто использовал только что созданный класс:

        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();

Единственная зависимость от этого решения - наличие служебного класса ProxiedSavedInvocationHandler котором расположены вся логика и новые API. Этот класс может быть расширен даже для включения API для прозрачного делегирования поведения другим InvocationHandler ; но необходимый минимум есть.

Ниже приведен полный рабочий пример применения этого решения:


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("	Running 'equals' inside proxy with:");
            System.out.println("	this: " + proxied);
            System.out.println("	other: " + 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));
    }
}

Есть идеи?

10000