Tuesday, October 03, 2006

Maven 2 + Hibernate + HSQLDB

Maven make projects very portable. Hibernate makes working with persistent objects simple. HSQLDB is a Java database that you can run embeded in other programs.

A problem with using Hibernate is it can take away some of the portability of your project. This is because you will need to provide a database for making your objects persistent. In doing so your test config files will be spec'd to a single database. What happens when someone runs the project's tests and does not have access to the test database? The tests will fail :( We want to have unit tests be used for all our hibernate objects. It is especially important to thouroughly test them, as they will be a central part of your projects functioning properly (especially web projects!).

Luckily Maven makes it easy to use one database for testing, and another for production. This is where HSQLDB can come in handy. You can create a hibernate config just for testing which connects to an in memory HSQL database. You will need the proper files in src/test/resources folder of your Maven 2 project. The files include the test version of your hibernate config file, and also the test hibernate mapping files that accompany your code. I put the hibernate mapping files into folders that mirror the packaging of the POJO object classes. When you run 'mvn package' the .hbm files will be placed in the same folder as the POJO class they belong to. Here is an example of my Maven 2 project's structure:

/project
pom.xml
...other files
/src
/main
/java
/some
/package
Foo.java
/resources
hibernate.cfg.xml
/some
/package
Foo.hbm.xml
/test
/java
/some
/testpackage
TestFoo.java
/resources
hibernate.cfg.xml
/some
/package
Foo.hbm.xml


So you can see that there are a set of hibernate files for the build and the test phase. Now in the test hibernate.cfg.xml file you will need to have the following properties set:


<!-- Database connection settings -->
<!-- HSQL DB -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:mem:aname</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

and...

<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<mapping resource="some/package/Foo.hbm.xml" />


These entries should have you now set up to use a in memory database for all your testing with hibernate. But before this will work you need to do one more thing.

Set up you Maven 2 project so that HSQLDB is a dependency. Added this dependency section to your project:

<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.1</version>
</dependency>


Note that you will not need to make any specific JDBC driver available. The HSQLDB dependency contains the proper driver!

Using this pattern you will be able to make very portable Maven/Hibernate projects. Users any place in the world will be able to check out your project and test it immediately. If they would like to test using their own database it is not hard for them to overwrite what is in the src/test/hibernate.cfg.xml file.

8 comments:

Doug Culnane said...

Great blog post this is exactly what I was trying to do. However I have a problem finding my JPA @NamedQueries... :-/

Small tip: The hsqldb dependancy scope only needs to be test.

<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
<scope>test</scope>
</dependency>

robottaway said...

Good point Doug, I mean on the testing scope bit. Can you elaborate some more on your problem. I doubt I will be able to provide much help... but I would love to hear the issue.

Rob O.

Unknown said...

how to use it with standalone mode

Unknown said...
This comment has been removed by a blog administrator.
Anonymous said...

Maybe I'm wrong but I see some weak points in this solution:

I have to maintenance simultanously 2 hibernate.cfg.xml files (for example when adding new mapped classes)

what If my project is a multitier JEE app with modules such as dao, logic, etc. ?

Adam Fortuna said...

Have you seen any other conventions on where to place hbm files? We're using Maven and looking to standardize this. At the moment keeping them in src/main means that much more custom script that has to be done to move them. ;/

robottaway said...

Thomas, you do not need to include the src/main/resources hibernate.cfg.xml file, you could just include this file on the classpath when using the Hibernate objects. This decouples the objects from a project specific configuration. If you are using other projects to represent layers such as dao or services then just include the Hibernate project's jar (in maven using dependencies!) and define the hibernate.cfg.xml you want for testing. Now you can test dao or service objects that rely on persistent Hibernate objects! I've used this approach in both daos and services with great success.

Now if you need to define multiple mappings for the objects in your Hibernate project you can go ahead and do that. Just make however many mapping files you need and then when you create a hibernate.cfg.xml file include the mappings you choose.

robottaway said...

Adam, not sure what you mean by "much more custom script...". You can put these files in src/main/resources if you like, but you must then change the hibernate.cfg.xml file to point to the files at the root of the classpath. If put here you can see them in target/classes when you run the compile or package commands, which means a packaged jar would have them in the root of the jar, and therefore the files would be on the root of the classpath. Does that help any?