January 03, 2005

Save five minutes: careful with auto-implementing Hibernate Interceptors

I'm writing this to stick a seed in your brain that will hopefully flower and save you five or ten minutes debugging if you ever run into the same issue. (Plus I wanted an excuse to use lots of screenshots.) The problem: after creating a Hibernate Interceptor in IntelliJ IDEA none of your object updates work.

I use IDEA to write all my Java. I love IDEA so much that I wish I could use it for Perl. (I think if good Perl people had IDEA they'd be without a doubt the most productive programmers on the planet and would eventually take over the world with sigils. And it would be good.)

One of the standard IDE shortcuts in IDEA allows you to create a file of a particular type:

Screenshot of IDEA: shortcut to create file

Each of the entries in the menu matches a file template in the system. You can add new file templates and use (I think) Velocity tags to ensure the passively generated file has some useful data -- it's in the right package, etc. Since we don't have a 'Hibernate Interceptor' type we just want a normal Java class and choose 'Class', after which we input the name:

Screenshot of IDEA: entering a class name

This creates the simplest class possible, although you'll notice I've customized the template with my name + email plus the standard company copyright language. (IDEA nicely folds this up for us -- it's lines 1-10.)

Screenshot of IDEA: result of creating a new class

Next, we just type in 'implements Interceptor' after the class name. IDEA is smart enough to know what 'Interceptor' classes we have in our project or any of the associated libraries, and makes them available with an 'Alt-Enter'.

Screenshot of IDEA: what happens when you ask to implement an interface

We choose 'net.sf.hibernate.Interceptor' and IDEA puts it in our import list for us. It also redlines the entire class declaration because we have unimplemented methods in a concrete class:

Screenshot of IDEA: giving you a readline because of unimplemented methods

We hit 'Ctrl-I' to have IDEA tell us what methods we need to implement. The next screenshot shows the methods from the single parent 'Interceptor', but IDEA is smart enough to find unimplemented methods from both other interfaces or parent abstract classes, but also from their parents.

Screenshot of IDEA: methods you can implement

IDEA will generate empty implementations for you. The implementation depends on the return type -- a 'boolean' return will have a single statement 'return false', an object return a 'return null', an array 'return new arraytype[0]':

Screenshot of IDEA: empty implementations for a few of the methods

The empty array type is where we get into trouble. Here we see where, in the empty implementation for 'findDirty()' which returns an int array:

Screenshot of IDEA: the culprit -- a bad 'findDirty' empty implementation

Most of the time when you implement a Hibernate interceptor you only want to actually do something in one or two of the methods like 'onSave()'. So you'll probably leave the empty implementation alone. And that's the problem -- if Hibernate gets back an empty array (vs null) it assumes nothing is dirty and doesn't perform any updates. I'm confident in declaring that this is not what you want. Of course, the fix is easy -- just replace the empty int array with 'null', which I'll gratuitously show:

Screenshot of IDEA: the good 'findDirty' implementation

Next: When you really, really, really want to be anonymous
Previous: Changing positions internally: does your company encourage it?