Есть ли какой-нибудь 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));
}
}