It can be pretty useful to supply dependencies to domain objects that you’re loading via Hibernate This is where Hibernate Interceptors come into play.
The Interceptor interface can be used to create classes that get informed when Hibernate is doing anything. Here’s a way you can use an Interceptor to do IoC work:
/** @see Interceptor#onLoad(Object, Serializable, Object[], String[], Type[]) */ public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { if (entity instanceof FactoryAware) { FactoryAware factoryAwareEntity = (FactoryAware) entity; factoryAwareEntity.injectFactory(createFactory()); } }
(Another choice for the method to override would be the instantiate method; however, you would need to instantiate the object yourself; this would be good for Constructor Injection, however)
You can also use onLoad for other neat tricks, such as expanding on saved data. Case in point: the application I’m currently working on stores user IDs. These user IDs are backed by data from our HR system, and in fact I treat them as Employee instances. The class is mapped as a component via Hibernate, with just the user ID persisted; the interceptor handles the task of populating Employee instances during the onLoad call.
A minor gripe is that Hibernate doesn’t have a default implementation of the Interceptor available. If you write a few of them, this could get annoying. So “here’s one I prepared earlier”:
/** * Default implementation of Interceptor * @author Robert Watkins */ public abstract class NullInterceptor implements Interceptor { /** @see Interceptor#onLoad */ public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { return false; } /** @see Interceptor#onFlushDirty */ public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException { return false; } /** @see Interceptor#onSave */ public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { return false; } /** @see Interceptor#onDelete */ public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { return; } /** @see Interceptor#preFlush */ public void preFlush(Iterator entities) throws CallbackException { return; } /** @see Interceptor#postFlush(Iterator) */ public void postFlush(Iterator entities) throws CallbackException { return; } /** @see Interceptor#isUnsaved(Object) */ public Boolean isUnsaved(Object entity) { return null; } /** @see Interceptor#findDirty */ public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { return null; } /** @see Interceptor#instantiate(Class, Serializable) */ public Object instantiate(Class clazz, Serializable id) throws CallbackException { return null; } }
This simply provides the recommend “don’t do anything” implementation as per the Interceptor’s Javadoc. As such, it is a safe implementation that other interceptors can subclass to get default behaviour for the methods that they don’t care about.
Is there any way that you could provide the Interceptor code that populates the Employee instances in the onLoad method? I’m basically facing the exact same issue.
Thanks!
Looks like Hibernate provides this functionality at least in 3.2.5…
org.hibernate.EmptyInterceptor