vendredi 18 mars 2016

Why I can call proxy.getClass() inside InvocationHandler's invoke() method?

This is a modified dynamic proxy example from "Thinking in Java".

import java.lang.reflect.*;

interface Interface { void foo(); }

class RealObject implements Interface {
    public void foo() {}
}

class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;
    public DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
    }
    @Override
    public Object 
    invoke(Object proxy, Method method, Object[] args) 
    throws Throwable {
        proxy.toString();
        return method.invoke(proxied, args);
    }
}

public class ProxyTest {
    public static void main(String args[]) {
        RealObject real = new RealObject();
        Interface proxy = (Interface)Proxy.newProxyInstance(
            Interface.class.getClassLoader(),
            new Class[]{ Interface.class }, 
            new DynamicProxyHandler(real));
        proxy.foo();
    }
}

In above example, I call toString() method inside invoke() method. As I expected, infinite recursion will happen because calling proxy's toString() method will invoke the Handler again.

This is how Bruce Eckel said in "Thinking in Java":

However, be careful when calling methods on the proxy inside invoke(), because calls through the interface are redirected through the proxy.

Exception details:

Exception in thread "main" java.lang.StackOverflowError
    at DynamicProxyHandler.invoke(ProxyTest.java:19)
    at $Proxy0.toString(Unknown Source)
    at DynamicProxyHandler.invoke(ProxyTest.java:19)
    at $Proxy0.toString(Unknown Source)
    ...

But, if I substitute proxy.getClass(); for proxy.toString();:

public Object 
invoke(Object proxy, Method method, Object[] args) 
throws Throwable {
    proxy.getClass();
    return method.invoke(proxied, args);
}

Everything is ok. No StackOverflowError. No infinite recursion.

I also tried to replace proxy.toString(); with proxy.hashCode(); or proxy.equals("foo");. They caused StackOverflowError either.

Why getClass() is different from toString(), hashCode(), and equals()?





Aucun commentaire:

Enregistrer un commentaire