I have no special talent. I'm only passionately curious - Albert Einstein
February 05, 2009
Completely Reverse Engineer your DAO Layer
Posted by Dave Malone
in Hibernate,
Spring,
Configuration,
Java,
Technology
I've been using Hibernate for about three and a half years now. When I began using Hibernate, I was hand-coding the Hibernate mappings and DAOs. The work was tedious, error prone, and time consuming. I've spent the time learning how to use both Middlegen and Hibernate tools to completely reverse engineer your Hibernate mapping files, the hibernate.cfg.xml file, the Model (beans), and all of the DAOs using a combination of Velocity and Freemaker templates to guide the code generation. I even went a step further and integrated Spring's HibernateDaoSupport into each of the DAOs.
I own the book Hibernate in Action, and the references in the back of the book listed a project called Middlegen which could assist you with your reverse engineering tasks. Of course, like most books, once it actually hits the shelves it's already out of date. When I looked up the Middlegen project, it already appears to be a dead project. The home page shows a last published date of April 7, 2006. I looked to the Hibernate site to see if they still referenced Middlegen. It appears that the original Middlegen project site is dead, and a new release (v3) is being managed at Codehaus.org. I've checked the Middlegen project page on Codehause.org as recently as today, and the project doesn't look like it was ever set up on that site.
After browsing the Hibernate site I noticed the Hibernate tools link. I was never able to get the Eclipse plugin working, so I decided to try out the Ant task. Of course, JBoss decided to write their own version of Middlegen, but after comparing the code and configurations that Hibernate tools generates vs. what Middlegen generates, I felt that Middlegen still offers more control over templating the DAOs, and Hibernate tools does the best job and offers the most flexibility when creating everything else.
To start, I'll include my buildfile, and then I'll explain some things which don't seem so obvious:
My Middlegen Ant build.xml
<?xml version="1.0"?>
<project name="Reverse Engineer Your Database" default="default" basedir=".">
<!-- The common classpath depends on the current environment -->
<path id="common.class.path">
<pathelement location="."/>
<pathelement location="src"/>
<fileset dir="lib" includes="*.jar"/>
</path>
<path id="toolslib">
<path location="lib/hibernate-tools.jar" />
<path location="lib/hibernate3.jar" />
<path location="lib/freemarker.jar" />
<path location="lib/jt400.jar" />
<path location="lib/mysql-connector-java-5.0.7-bin.jar" />
</path>
<taskdef
name="middlegen"
classname="middlegen.MiddlegenTask"
classpathref="common.class.path"
/>
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="common.class.path" />
<target name="clean">
<delete dir="src/com/yourpackage/dao" />
<delete dir="src/com/yourpackage/model" />
<delete file="src/cfg/hibernate.cfg.xml"/>
<mkdir dir="src/com/yourpackage/model"/>
<mkdir dir="src/com/yourpackage/dao"/>
</target>
<target name="middlegen" depends="clean" description="creates Hibernate mapping files from database metadata">
<middlegen
appname="YourAppName"
gui="FALSE"
databaseurl="jdbc:mysql://localhost:3306/yourdb"
driver="com.mysql.jdbc.Driver"
username="yourusername"
password="yourpackage">
<!-- Optionally declare table elements -->
<!-- Optionally declare many2many elements -->
<!-- One or more plugins -->
<!-- Hibernate Plugin -->
<hibernate
destination="src"
package="com.yourpackage.model"
javaTypeMapper="middlegen.plugins.hibernate.HibernateJavaTypeMapper"
genXDocletTags="false">
<hibernateDAO />
</hibernate>
</middlegen>
</target>
<target name="hbm2cfgxml" description="Generate hibernate.cfg.xml from hibernate.properties and hbm.xml files" depends="middlegen">
<hibernatetool destdir="src">
<configuration propertyfile="src/cfg/hibernate.properties">
<fileset dir="src">
<include name="**/*.hbm.xml"/>
</fileset>
</configuration>
<hbm2cfgxml destdir="src/cfg/"/>
</hibernatetool>
</target>
<target name="hbm2java" description="Generate POJOs from .hbm files." depends="hbm2cfgxml">
<hibernatetool destdir="src">
<configuration configurationfile="src/cfg/hibernate.cfg.xml"/>
<hbm2java />
</hibernatetool>
</target>
<target name="hbm2dao" description="Generate DAOs">
<hibernatetool destdir="src">
<configuration configurationfile="src/cfg/hibernate.cfg.xml"/>
<hbm2dao />
</hibernatetool>
</target>
<target name="cleanup" description="Moves DAOs to dao package">
<move todir="src/com/yourpackage/dao">
<fileset dir="src/com/yourpackage/model" includes="*DAO.java" />
</move>
<replaceregexp
match='package com.yourpackage.model;'
replace='package com.yourpackage.dao;'
byline="true">
<fileset dir="src/com/yourpackage/dao" includes="*.java" />
</replaceregexp>
</target>
<target name="default" depends="hbm2java, cleanup" />
</project>
Nested deep in the "middlegen" target is the task which actually generates your DAO files. You can optionally control the generation of the DAOs using a Velocity template. To control the generation of the DAOs you will create a file called hibernate-dao.vm. To control the generation of the hbm.xml files, you will create a file called hibernate.vm. Both must be placed in a middlegen.plugins.hibernate package and be visible to your Ant projects classpath when you're running the build script. I've included my templates for reference:
hibernate-dao.vm
hibernate.vm
The hibernate.properties file referenced in the "hbm2cfgxml" target is a basic Hibernate properties file. The only required properties in this file are:
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/yourdatabase
hibernate.connection.username=yourusername
hibernate.connection.password=yourpassword
These properties are just used to generate the nicer hibernate.cfg.xml. You will also need to point to the directory which contains your *.hbm.xml files, so that this task can build the mapping elements.