Monday, April 2, 2012

Hibernate4 SessionFactoryBuilder gotcha

Just upgraded one of our projects to Spring 3.1.1 and Hibernate 4.1.1 today and ran into a small problem that ate up some time.

Symptom:

It appeared as if all of my hibernate <property>'s in hibernate.cfg.xml were suddenly not being picked up -- they were just silently being ignored.

So for example, for our unit tests, we run Derby with hibernate.hbm2ddl = create so that the schema is generated dynamically each time. In Hibernate 3.6 we used two files: hibernate.cfg.xml (packaged in the jar, not for customers) and hibernate.local.cfg.xml (placed in the customer's etc directory on the class path for support/production time overrides, etc.).

Well in migrating to Hibernate4 I took advantage of Spring's new hibernate4.LocalSessionFactoryBuilder class to help build my metadata and I got rid of my hibernate.cfg.xml entirely.

I used it like so:

    @Bean
    public SessionFactory sessionFactory() {
        return new LocalSessionFactoryBuilder(dataConfig.dataSource())
            .scanPackages(DatabasePackage)
            .addPackage(DatabasePackage)
            .addProperties(dataConfig.hibernateProperties())
            .addResource("hibernate.local.cfg.xml")
            .buildSessionFactory();
    }
And I had a hibernate.local.cfg.xml in my src/test/resources that looked like:
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.hbm2ddl.auto">create</property>
  </session-factory>
</hibernate-configuration>

But it wasn't being picked up! I tried adding mappings in to it and those were picked up. Finally after digging through the Hibernate source I realized the problem. Adding hibernate.cfg.xml's through addResource only processes class mappings -- it ignores properties and listeners etc. However, you can add hibernate.cfg.xml's through the the .configure method and those are still processed as they were before Hibernate4.

    @Bean
    public SessionFactory sessionFactory() {
        return new LocalSessionFactoryBuilder(dataConfig.dataSource())
            .scanPackages(DatabasePackage)
            .addPackage(DatabasePackage)
            .addProperties(dataConfig.hibernateProperties())
            .configure("hibernate.local.cfg.xml")
            .buildSessionFactory();
    }

I couldn't find this well documented anywhere, nor was it specifically mentioned on the migration guide as a consideration. They do mention not paying attention to event listeners anymore, but don't mention properties.

No big deal -- just lost some time :(



Steve