Member Menu
 
 Monthly JBoss newsletter:
 
Java Persistence with Hibernate
CaveatEmptor

Mapping a Dynamic Proxy

This page explains how to load and store instances that are wrapped with a JDK dynamic proxy.

First, you need an interface:

public interface FooInterface {

    public Long getId();
    public void setId(Long id);
    public String getBar();
    public void setBar(String bar);

}

Next, a concrete class that implements this interface:

public class Foo implements FooInterface {

    private Long id;
    private String bar;

    public Foo() {}

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }


    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }
}

A proxy is a class that wraps a concrete instance that implements a given interface. This is a possible proxy:

public class FooProxy implements InvocationHandler {

    Object obj;

    public FooProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws
            Throwable {
        try {
            // Do something on real object
            return m.invoke(obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw e;
        }
    }

    public static Object newInstance(Object obj, Class[] interfaces) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                                      interfaces,
                                      new FooProxy(obj));
    }
}

Note that this proxy implementation does nothing, in other words, it does not implement any additional functionality. Every method called on the proxy is directly passed on to a method call on the real object. I also included a factory method.

Let's map this with Hibernate XML. You map the interface:

<hibernate-mapping>

<class name="FooInterface"
       table="FOO">

    <id name="id" column="FOO_ID" type="long">
    <generator class="native"/>
    </id>

    <property name="bar" column="BAR"/>

</class>

</hibernate-mapping>

Hibernate will use the getter and setter methods defined by that interface as property accessors. Finally, you need a Hibernate Interceptor to do the proxy magic when loading and storing an object:

public class FooProxyInterceptor extends EmptyInterceptor {

    public String getEntityName(Object object) {
        if (Proxy.isProxyClass(object.getClass()) && object instanceof FooInterface)
            return FooInterface.class.getName();
        return super.getEntityName(object);
    }

    public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
        if (entityName.equals(FooInterface.class.getName())) {
            Foo newFoo = new Foo();
            newFoo.setId((Long)id);
            FooInterface foo = (FooInterface)
                  FooProxy.newInstance(newFoo, new Class[]{ FooInterface.class });
            return foo;
        }
        return super.instantiate(entityName, entityMode, id);
    }

}

When saving an object, getEntityName() is called. If we would use the default in Hibernate, it would look for a mapping of FooProxy - we don't have that. If a proxied object is saved we instead return the name of the mapped interface.

When loading an object, a concrete instance of Foo is needed, and it has to be wrapped in a proxy.

© Copyright 2006, Red Hat Middleware, LLC. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc. [Privacy Policy]