02/12/2008

Proxy Method Resolving Order

I noticed interesting behavior of method resolving order, which reflects interface order in java.lang.reflect.Proxy.newProxyInstance(...) call. It fact, it is described in Sun's java guide: Dynamic Proxy Classes: Methods Duplicated in Multiple Proxy Interfaces

Supose, there are two interfaces (A and B) with same signature and we have created a proxy that implements this interface in order {A,B}.

When we cast a proxy to class A and invoke it's method, the InvocationHandler says that we invoke a method from interface A (as expected).

But when we cast a proxy to class B and invoke it's method, the InvocationHandler says that we invoke a method from interface A again! Here I'd expect the InvocationHandler will say that we invoking a method of interface B and it's strange for me.

Order of appearing interfaces in proxy instance factory method does matter. Following program demonstrates it:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyMethod {

interface A {
void doSomething();
}

interface B {
void doSomething();
}

static class EchoHandler implements InvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method = " + method);
return null;
}
}

public static void main(String[] args) {
Object proxy1 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{B.class, A.class},// The difference
new EchoHandler());

Object proxy2 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{A.class, B.class},// The difference
new EchoHandler());

System.out.println("\nproxy1 intfs = " + Arrays.asList(proxy1.getClass().getInterfaces()));
((A) proxy1).doSomething();
((B) proxy1).doSomething();

System.out.println("\nproxy2 intfs = " + Arrays.asList(proxy2.getClass().getInterfaces()));
((A) proxy2).doSomething();
((B) proxy2).doSomething();
}
}

Returns following result:

proxy1 intfs = [interface ProxyMethod$B, interface ProxyMethod$A]
method = public abstract void ProxyMethod$B.doSomething()
method = public abstract void ProxyMethod$B.doSomething()

proxy2 intfs = [interface ProxyMethod$A, interface ProxyMethod$B]
method = public abstract void ProxyMethod$A.doSomething()
method = public abstract void ProxyMethod$A.doSomething()

This behavior allows to build object wrapper as dynamic proxies easily. Interface of the object being wrapped should be passed first to the proxy factory method. So, if methods of the wrapped object's interface is passed to the invocation handler - just invoke them on a wrapped objects. Other methods should be handled differently by invocation handler.

No comments:

Post a Comment

redirect