Как получить «прокси» объект из существующего динамического прокси - PullRequest
0 голосов
/ 14 мая 2019

Есть ли какой-нибудь 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 Ответ

0 голосов
/ 16 мая 2019

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

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

    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("\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));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...