Blog About Contact

Using Bottom-Up Iterative Object/Database Layer With hbm2java and warp-persist

Published Tue, 25 Aug 2009

This post sort of follows on from my last one - for the project I'm currently working on at work, we have a very large legacy database (1500+ tables) on top of which we are implementing a new business layer (Java/Guice).

Due to the legacy data structures (which are mostly in need of major refactoring, that can only occur in a long-term iterative fashion), we are completely segmenting the DAO layer from the business domain layer. The DAO layer and associated @Entity beans are generated automatically (and frequently) using the hbm2java tool which is part of Hibernate. To make things even more complex, our business layer also supports multiple logical databases.... We are using Guice, and the excellent warp-persist library to manage the JPA transactions and bootstrapping across these multiple databases (multi-unit support is relatively new in warp-persist).

The problem then comes though - unless we manually add all of our 1000's of @Entity beans to the JPA configuration for each persistence unit (which is a potential source of bugs, and a pain in the ass), how do we figure out which beans belong to which database unit? Well annotations is the way that warp-persist implements this, unfortunately, hbm2java doesn't know that... (i.e. it won't add the? annotations? against the relevant classes).

This is actually easily solved using the same trick with Ant and the regex replacement from my last post...

   <target name="gen_hibernate" description="generate hibernate classes">
        <hibernatetool>
            <jdbcconfiguration revengfile="src/hibernate.reveng.xml"
                               configurationfile="src/hibernate.cfg.xml"
                               packagename="com.mycom.db.model"
                   detectmanytomany="true"
                               />
            <hbm2java destdir="src" ejb3="true" jdk5="true"/>
        </hibernatetool>
        <loadfile property="javaheader" srcFile="lib/standardheader.txt"/>
        <replaceregexp match="^package " 
                       replace="${javaheader}// DO NOT EDIT THIS FILE - THIS CODE IS AUTO-GENERATED${line.separator}package ">
            <fileset dir="src/com/mycom/db/model">
                <include name="**/*.java"/>
            </fileset>
        </replaceregexp>
        <replaceregexp match="/\*\*.*generated by hbm2java.*\*/" 
                       flags="sm" 
                       replace="/**${line.separator} * @version $Id$ ${line.separator} */${line.separator}">
            <fileset dir="src/com/mycom/db/model">
                <include name="**/*.java"/>
            </fileset>
        </replaceregexp>
        <replaceregexp match="@Entity" 
                       replace="@Entity @MyDbUnit">
            <fileset dir="src/com/mycom/db/model">
                <include name="**/*.java"/>
            </fileset>
        </replaceregexp>
        <replaceregexp match="import javax.persistence.Entity;" 
                       replace="import javax.persistence.Entity; import com.mycom.db.MyDbUnit;">
            <fileset dir="src/com/mycom/db/model">
                <include name="**/*.java"/>
            </fileset>
        </replaceregexp>
    </target>

You'll notice I threw in a couple of bonuses there too... the following changes are automatically made to all of the generated code -

  1. Our "standard header" (copyright / licence info) is added to the top of the file above the package .... descriptor.
  2. The @version $Id$ Javadoc tag is added to the class level Javadoc (this is assuming you're using SVN or CVS - replace as necessary).
  3. The database unit annotation (@MyDbUnit in this case) is added next the @Entity annotation.
  4. Finally we add the import for the @MyDbUnit annotation (this would only be required if it's in a separate package - which it in our case it is).

We then copy / replicate this job for each database in the system (with appropriately separate hibernate.cfg.xml and hibernate.reveng.xml configurations).

Well I think this takes the cake for the most esoteric and narrow detail blog post yet... but my whole goal in setting up and posting to this blog is for my own future reference; if other people find it useful then that's great, but really when I implement something that was kinda interesting, tricky, or indeed esoteric, then this is my own reference for later. YMMV.


About the Author

Richard Nichols is an Australian software engineer with a passion for making things.

Follow him on twitter or subscribe by RSS or email.

You might also enjoy reading -


Discuss / Comment

No one has commented yet.

Add a comment

  • {{e.error}}

Thanks for your comment!/

Required.
Valid email address required.
Required.
Posting message, please wait...