Hibernate + Middlegen Roundtrip Development applied

In Hibernate Roundtrip Development, a scenario is presented to generate (Hibernate) POJO objects from a (legacy) database, also known as a bottom-up approach:

RoundtripDevelopment

We applied this strategy to a MSSQL server database with a jTDS JDBC driver. We discuss the steps involved, analyse the results produced, and stipulate a pending issue.

The following refs were very helpful:

Our build.xml is based on the sample airline application that comes with the Middlegen distribution. The MSSQL specific settings include:

   <property file="${basedir}/build.properties"/>
   <property name="lib.dir" value="${basedir}/lib"/>

   <property name="database.driver.file"
             value="${lib.dir}/jtds-0.9-rc1.jar"/>
   <property name="database.driver.classpath"
             value="${database.driver.file}"/>
   <property name="database.driver"
             value="net.sourceforge.jtds.jdbc.Driver" />
   <property name="database.url"
             value="jdbc:jtds:sqlserver://amis_machine_name" />
   <property name="database.userid"
             value="amis_username"/>
   <property name="database.password"
             value="amis_passwd"/>
   <property name="database.schema"
             value="dbo"/>
   <property name="database.catalog"
             value="RemoteUren"/>

The middlegen target itself is largely left unaltered:

   <target
      name="middlegen"
      description="Run Middlegen"
      unless="middlegen.skip"
      depends="init,fail-if-no-xdoclet-1.2"
   >
      <mkdir dir="${build.gen-src.dir}"/>

      <taskdef
         name="middlegen"
         classname="middlegen.MiddlegenTask"
         classpathref="lib.class.path"
      />

      <middlegen
         appname="${name}"
         prefsdir="${src.dir}"
         gui="${gui}"
         databaseurl="${database.url}"
         initialContextFactory="${java.naming.factory.initial}"
         providerURL="${java.naming.provider.url}"
         datasourceJNDIName="${datasource.jndi.name}"
         driver="${database.driver}"
         username="${database.userid}"
         password="${database.password}"
         schema="${database.schema}"
         catalog="${database.catalog}"
      >

         <html destination="${build.html.dir}"> />

         <hibernate
            destination="${build.gen-src.dir}"
            package="${name}.hibernate"
            genXDocletTags="true"
         />

      </middlegen>

      <mkdir dir="${build.classes.dir}"/>
   </target>

According to the above picture, we can even go one step further using the hbm2java tool. To this extent, we defined an additional task in the build.xml:

   <target name="hbm2java" depends="middlegen" description="Generate .java from .hbm files.">
      <taskdef
         name="hbm2java"
         classname="net.sf.hibernate.tool.hbm2java.Hbm2JavaTask"
         classpathref="lib.class.path"
      />

      <hbm2java output="${build.gen-src.dir}">
         <fileset dir="${build.gen-src.dir}">
            <include name="**/*.hbm.xml"/>
         </fileset>
      </hbm2java>
   </target>

After copying the jDTS jar to the lib dir (where all the middlegen-related jars reside), we could simply invoke middlegen by starting ant. We did not make use of the GUI, since there is no need for us to fine-tune the generated code (at least, not yet).

According to a Hibernate-knowledgeable collegue (Jasper Fontaine), applying Middlegen to the tables in the database resulted in clean and readable code in both the hbm2java-generated POJOs (plain old Java objects, containing private member variables representing the DB-columns with associated getters and setters) and the Hibernate mapping files. Both the POJOs and mapping files come close to what we would have been coding by hand.

However, a more general concern might be the fact that this way a layer of objects is procuded, which has a one-to-one relation with the tables in the RDBMS. This implies that a change in the tables will have consequences for the code that relies on those table-representing objects!

We have decided to keep working with Hibernate (and Middlegen), since its benefits (no need to write low-level data access code + transaction support) outweigh the disadvantages here.

Moreover, this drawback has largely been compensated in our case by employing the DAO (Data Access Object) pattern. In principle, this still leaves us the choice of JDBC, Hibernate, Toplink, or any other technology for the implementation of our DAO interfaces at a later stage (as a matter of fact, we used this approach before in a “study/trial application”, where we employed an abstract factory design pattern to be able to easily switch between these different “DAO providers”, see also this post).

One issue remains pending though. In the sample airline application that comes with the Middlegen distribution, it is possible to generate a Struts layer as well, departing fromt the tables in the database. As a first set-up, we would like to mimic this approach. However, the airline application is based on EJBs. Currently we did not succeed in constructing a similar build.xml file for our Hibernate-based solution, since the generated Struts Action Java classes are full of EJB-related references, despite the fact that our build.xml does not contain any EJB-related entries.

7 Comments

  1. Ratnesh Mathur May 7, 2008
  2. Zeger Hendrikse March 31, 2005
  3. Zeger Hendrikse March 30, 2005
  4. Sarah March 25, 2005
  5. Zeger Hendrikse November 26, 2004
  6. Mushtaq November 25, 2004
  7. Zeger Hendrikse November 17, 2004
  8. Pingback: » Hibernate and Middlegen revisited April 7, 2005