views:

52

answers:

2

I was dealing with hibernate, trying to figure out the run-time class behind proxied instances by using the visitor pattern. I then came up with an AbstractVisitable approach, but I wonder if it will always produce correct results.

Consider the following code:

interface Visitable {
    public void accept(Visitor v);
}

interface Visitor {
    public void visit(Visitable visitorHost);
}

abstract class AbstractVisitable implements Visitable { 
    @Override
    public void accept(Visitor v) {
        v.visit(this);
    }
}

class ConcreteVisitable extends AbstractVisitable {
    public static void main(String[] args) {
        final Visitable visitable = new ConcreteVisitable();
        final Visitable proxyVisitable = (Visitable) Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class<?>[] { Visitable.class }, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        return method.invoke(visitable, args);
                    }
                });
        proxyVisitable.accept(new Visitor() {
            @Override
            public void visit(Visitable visitorHost) {
                System.out.println(visitorHost.getClass());
            }
        });
    }
}

This makes a ConcreteVisitable which inherits the accept method from AbstractVisitable. In c++, I would consider this risky, since this in AbstractVisitable could be referencing to AbstractVisitable::this, and not ConcreteVisitable::this. I was worried that the code under certain circumstances would print class AbstractVisible. Yet the code above outputs class ConcreteVisitable, even though I hid the real type behind a dynamic proxy (the most difficult case I could come up with). Is the abstract visitor approach above guaranteed to work, or are there some pitfalls with this approach?

What guarantees are given in Java with respect to the this pointer?

+2  A: 

this always points to this object, as you might guess. Which type in the hierarchy you use it from is irrelevant, unless you're using it to reference non-virtual things (like private fields/methods, or God forbid, static methods). getClass() is virtual.

Now I expect maybe you're confusing the behaviour of this for thinking Java has multiple dispatch. It doesn't. If you change your Visitor to this:

class Visitor {
    public void visit(Visitable visitorHost);
    public void visit(ConcreteVisitable visitorHost);
}

And then implemented it like this:

public void visit(Visitable visitorHost) { 
   System.out.println("Visitable"); 
}
public void visit(ConcreteVisitable visitorHost) {
   System.out.println("ConcreteVisitable"); 
}

It would indeed print "Visitable", not "ConcreteVisitable" since Java does not perform double dispatch.

Mark Peters
Nice wrap-up the 'getClass() is virtual' was the key fact that I oversaw.
disown
A: 

Your dynamic proxy passes the accept(...) call through to the underlying Visitable, which then calls visit(...), passing itself as the argument. The proxy is never involved in anything except passing through the accept() call, so by the time it gets to the implementation of the visit(...) method, the Visitable being dealt with is the concrete instance, shorn of the proxy.

Jon Moore