I recently decided to try out Hibernate's annotation-based validation framework. It seems like a great solution for ensuring consistent validation of the domain model regardless of the presentation tier (web interface, web service, etc.). It very much reminds me of the declarative validation available within Rails model objects.

To make a long story short, things did not go as well as I had hoped using a Hibernate Core 3.2.0 CR2 and Hibernate Annotations 3.2.0 CR1 combination. I struggled for hours trying to figure out why I was getting a "not-null property references a null or transient value" error rather than a validation error when attempting to use the NotNull validation annotation. Eventually I discovered the problem was not that the NotNull validation wasn't working properly, but that it wasn't running at all.

In order for the annotation-based validation framework to execute, Hibernate Annotations provides a ValidatePreInsertEventListener and ValidatePreUpdateEventListener to fire the annotation validations prior to persisting any changes to the domain model. "Pre-insert" and "pre-update" events are fired after other events, in this case SaveOrUpdateEvent(s). By default, Hibernate uses the DefaultSaveOrUpdateEventListener, which is an extension of AbstractSaveEventListener. The AbstractSaveEventListener checks for null values corresponding to non-nullable database columns ( AbstractSaveEventListener:284 ) before adding the insert or update events to the execution queue( AbstractSaveEventListener:290 ) responsible for triggering pre-insert or pre-update event listeners. In case that didn't make complete sense, the bottom line is the Hibernate Core checks entities against the null constraints of the database before the annotation-based validation framework has a chance to run.

Luckily, there is a workaround, although it feels like a bit of a hack. As I mentioned previously, the DefaultSaveOrUpdateEventListener gets a chance to run before any "pre-insert" or "pre-update" events so we can use that to our advantage. The following SaveOrUpdateEventListener simply extends the Hibernate Annotations-provided ValidateEventListener and calls the validation method on "save-update" events rather than "pre-insert" and "pre-update" events.

``` java public class ValidationEventListener extends ValidateEventListener implements SaveOrUpdateEventListener { public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { final SessionImplementor source = event.getSession(); final Object object = event.getObject(); if (!source.getPersistenceContext().reassociateIfUninitializedProxy(object)) { // only validate the entity if it has been changed final Object entity = source.getPersistenceContext().unproxyAndReassociate(object); super.validate(entity, event.getSession().getEntityMode()); } } } ```

One extemely important thing to remember when using this workaround is that you must configure the DefaultSaveOrUpdateEventListener as the second "save-update" listener (following the ValidationEventListener) or your objects will never be persisted.