Thursday, March 6, 2008

Supporting Proxy Equality

Yesterday's post talked about how using the equals(Object) method to compare two Proxy objects always evaluates to false, even when the receiver and the parameter are the same instance. Today's topic is how to implement the InvocationHandler interface such that the equals(Object) method is handled correctly.

The solution is to intercept the invocation of the equals(Object) method and invoke it with an unwrapped receiver and parameter. Here's how...

public class MyInvocationHandler extends Object implements InvocationHandler {
private Object object;

public MyInvocationHandler(Object object) {
super();
this.object = object;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
String name = method.getName();
if (name.equals("equals") && args.length == 1) {
MyInvocationHandler handler = toMyInvocationHandler(args [ 0 ]);
if (handler != null) {
Object[] parameters= new Object[] {
handler.object
};
result = method.invoke(object, parameters);
}
}

if (result == null) {
result = method.invoke(object, args);
}

return result;
}

private MyInvocationHandler toMyInvocationHandler(Object parameter) {
InvocationHandler handler = Proxy.getInvocationHandler(parameter);
boolean valid = handler instanceof MyInvocationHandler;
if (valid == false) return null;
MyInvocationHandler myHandler = (MyInvocationHandler) handler;
return myHandler;
}
}

Rather than anonymously implementing the InvocationHandler interface, we have the class MyInvocationHandler. The object field is used to store the object that is being proxied.

We must intercept the invocation of the equals(Object) method, and where the parameter is an instance of MyInvocationHandler, we must invoke the Method, passing as a parameter the MyInvocationHandler instance's object field.

This technique of unwrapping the parameter Proxy only works when the proxy is one that has an invocation handler that is an instance of MyInvocationHandler. In cases where the parameter is not an appropriate proxy, execute continues as normal in the invocation handler.

1 comment:

Anonymous said...

Hum - doesn't work well no? Doing this, you bypass the proxy in equals, so if equals() calls other methods of the object, it's not through the proxy anymore.
Looks to me it's only safe if your object class does not overwrite equals().

Planet Eclipse

Jazz Community News