Monday, September 20, 2010

Multiple Hibernate configuration files

I must be living in a stone age, at least, with regard to Java persistency. Recently I had to add another EJB module to an application that is using Hibernate as its persistency. The application uses a much recommended HibernateUtil helper class to start up and access the org.hibernate.SessionFactory. It is almost a copy-paste from the Hibernate tutorial.

In the newly added module I want to add some HQL queries and possibly some more mapped classes. I do not want to change the existing configuration file because the new module is optional. Besides, the existing configuration lives in a different maven module. So adding new queries is possible, albeit not "clean", but adding new mapped classes is out of the question. I have to have a second configuration file but I want it to be available via the same HibernateUtil class. I do not want to copy-paste it into my module.

Quick googling shows that I am not alone but proposed solutions (at least linked from the first couple of result pages) are not really satisfying. Duplicating HibernateUtil was there as well as using org.hibernate.cfg.Configuration API. Or using a system property that defines which file to load. Yeah, this would work, except that I did not like it either: I would need to define the property in multiple places (unit tests or appserver deployment) depending on which modules are packaged. Of course, at the moment the application has max. 2 modules with a configuration file, so I can rely on a "default property value" when the new EJB module is not deployed and set the property explicitly only when the new EJB module is deployed. Will it work? Yes. But for the rest: no thanks.

Instead I have changed HibernateUtil to have more or less the following:


private static SessionFactory buildSessionFactory() {
Configuration cfg = new Configuration();

try {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration en = ldr.getResources("hibernate.cfg.xml");
Set processed = new HashSet();

while (en.hasMoreElements()) {
URL next = en.nextElement();

if (processed.add(next)) {
cfg.configure(next);
}
}
if (processed.isEmpty()) {
FAIL
}

return cfg.buildSessionFactory();
}
catch (Exception ex) {
FAIL
}
}


I do not need to use any system properties. The code just "discovers" the configuration files and works correctly in unit tests and in the real container, with the new EJB module or without it.

No comments:

Post a Comment