Search This Blog

Hades: DRY principle in JPA/Spring development

It's almost two weeks after great Javarsovia 2010 conference, but before I write few words about this event, let me mention about really clever library called Hades. I owe you this after my attendance in GeeCON 2010, where I discovered this tool during its author talk.

DRY stands for Don't Repeat Yourself and if you were developing in JPA for a while you have violated this principal several times. Take for example this piece of code:

Although IntelliJ IDEA has a wonderful support for JPA (have you noticed this little popup suggesting me the proper named query parameter name since?), I still have to write the same boilerplate code over and over. Basically for each entity object I need a DAO class and 90% of them look the same except they have different entity type. Same CRUD, same paging and sorting logic, same unit tests, similar queries. We are getting bored after writing fifth or tenth DAO like this, especially if we are lazy (which is good!) So Hades provides nice abstraction, at least all your DAOs would follow same naming convention:

Now run the test, it should pass. That's right, we haven't written even single line of DAO code and still our MoneyTransferDao, injected in line 10, works perfectly! The whole magic is hidden under line 39 of Spring context file. hades:dao-config element discovers all interfaces extending org.synyx.hades.dao.GenericDao<T, PK extends Serializable> and dynamically implements them based on their generic types. We automatically get methods like:

Yep, Hades also provides built in support for paging and sorting – especially annoying when has to be implemented and tested manually for several entities.

OK, to be honest, there was no magic in what we have seen until now and you might have even written similar utilities for your internal usage. Although GenericDao has some built in methods that cover, let's say, 50% of typical queries, what about the rest? What if I would like to find all money transfers with amount greater than given value?

Where to put the implementation of this custom DAO method? Well, now the magic part begins – nowhere! Similar to GORM, Hades will parse this method name and create the query for you. All you have to do is to follow some naming convention. No custom queries, no boilerplate code. Hades will even set the parameter for you. It's such a clever tool, that simply by adding argument of type Pageable Hades will include paging clauses (like TOP, LIMIT, OFFSET, etc.):

So, Hades can transparently implement basic CRUD operations with sorting/paging support. It can also synthesize queries based only on interface method name and arguments. But once you discover that this feature is very limited (for instance it does not support Not, Like, IsNull, In and other modifiers known from GORM, see issue #274), you'll eventually end up with a need for a custom JPA query like this:

The implementation is trivial (see screenshot at the beginning of this article), so Hades implements this method for us as well. Name of the method matches name of the named query (prefixed by the entity name), which is enough for Hades. Few lines of code (repeated hundreds of times) are saved.

But what if you really want to implement custom DAO method, but still having all other methods implemented for you? There are two reasons: do some validation and parameters transformation before the query is executed and post-process results after query execution. The latter reason can be often eliminated using not very well known JPA query language feature. Take for instance this query:

It will return List<Object[]>, which isn't very object-orientish. Instead, our DAO layer should do some transformation and return more user friendly object. JPA can do this for you with this simple expression:

RawMoneyTransfer is any Java object (not necessarily JPA entity) with constructor matching given parameters being only requirement. But once again, what if you really need custom DAO method? For example JPA does not define any date expressions, so there is no straightforward way to define "30 days before today" when generating report for last month in JPA QL. Unfortunately, Hades way of defining custom DAO methods is troublesome and a bit counterintuitive. I will open an issue and try to introduce simpler (although harder in implementation) solution. Meanwhile take a look at great Hades reference documentation for further details.

Hades also has support for entity auditing, but Envers, being part of Hibernate portfolio, is probably more mature solution. As of version 2.0 it also has built in support to participate in Spring transactions. As you have seen, Hades aims to increase your productivity by writing less code, less unit tests (comprehensive unit testing of Hades-generated methods isn't necessary) and promoting convention over configuration approach. It still has some limitations but give it a try, I recently will.

@Anonymous: I haven't tried but I actually asked Oliver Gierke (the author of Hades himself) about it some time ago and he confirmed it can be used outside of Spring (it is basically a layer around JPA). Never tried it though.

BTW please take a look at Spring Data JPA, which is a next generation of Hades written by the same people.

Good post mate. By the way I have seen couple of misuses of DRY pattern where people just combined code for two completely different thing which looks same in code, an example is validating telephone number with account number when both contains numbers, which is not correct. I have also blogged about 10 OOOPS and SOLID design principle for java developers let me know how do you find it.