I have finally figured this out. This solution would have also worked for generating the Abstract domain classes (another post). This turns out to be pretty easy. I used a simple customized template to do this without writing any java code. It is a real shame that the documentation for Hibernate-Tools does not have more explicit information on how to use custom templates. It could really use some _well explained_ examples. It took me a long time to figure this out and it was a very simple piece of information that was needed to figure this out - the semantics of the templatepath attribute of the hibernate-mapping tab. So here is what I found.
Generation of the artifacts in Hibernate-Tools (java, hbm.xml, cfg.xml, etc.) happens through a template system. By customizing the templates, you can change the resulting artifacts that are generated. The current Hibernate-Tools uses the freemarker template system. You can read the freemarker docs, but I found that simply by looking at the templates, I could figure out how to modify them. If you download the Hibernate-Tools source, it will contain the templates. Relative to the root of the project folder, the path to the templates is "./tools/src/templates/".
The structure of the templates folder looks like this
templates/dao - templates for generating daos via <hbm2dao/>
templates/doc - templates for generating documentation
templates/dot - templates for generating ...
templates/hbm - templates for generating mapping files via <hbm2hbmxml/>
templates/lint - not sure
templates/pojo - templates for generating java via <hbm2java/>
The two most important points when using customized templates for artifact generation are;
1. The ant tools task must specify the root of the templates path using the templatepath attribute of the <hibernatetool> tag. So, the path you specify would potentially have the /dao, /doc, /dot, etc. folders within it. For example, my project folder structure looks like this;
project/src - my source
project/src/templates - my templates folder
project/src/templates/hbm - my mapping file templates
project/src/templates/hbm/hibernate-mapping.hbm.ftl - this is the one template file I customized.
So, my ant tools task definition uses a templatespath attribute like this;
Code:
<hibernatetool destdir="src" templatepath="src/templates/">
Note that the path starts at the project root and leads to the folder containing the template subfolders.
2. Your customized template(s) must have the same name as the original template and must be in the same relative path as the original. You only need to provide the templates that you have customized. In otherwords, don't bother to copy all the templates from the Hibernate-Tools source to your own templates folder and then customize a few. You just need the ones that you will customize. When the Hibernate-Tools tasks (<hbm2java/>, <hbm2hbmxml/>, etc.) run, they will first look in the folder specified by the templatepath attribute for the template and if it is not found, they will get the standard one from the Hibernate-Tools.jar.
In my case, I was generating hibernate mapping files from the database using <hbm2hbmxml/> I simply wanted to make my hibernate mapping files using the default-access="field" attribute in the <hibernate-mapping/> tag, to force hibernate to use direct field access rather than getter/setter access. The first thing I had to do was identify the template that was used to generate the hbm.xml file. I looked for likely suspects in the templates/hbm folder. I found templates/hbm/hibernate-mapping.hbm.ftl. It looks like this:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated ${date} by Hibernate Tools ${version} -->
<#if hmgs?exists && hmgs.hasNonDefaultSettings()>
<hibernate-mapping
<#if hmgs.hasDefaultPackage()>
package="${hmgs.defaultPackage}"
</#if>
<#if hmgs.hasSchemaName()>
schema="${hmgs.schemaName}"
</#if>
<#if hmgs.hasCatalogName()>
catalog="${hmgs.catalogName}"
</#if>
<#if hmgs.hasNonDefaultCascade()>
default-cascade="${hmgs.defaultCascade}"
</#if>
<#if hmgs.hasNonDefaultAccess()>
default-access="${hmgs.defaultAccess}"
</#if>
<#if !hmgs.isDefaultLazy()>
default-lazy="false"
</#if>
<#if !hmgs.isAutoImport()>
auto-import="false"
</#if>>
<#else>
<hibernate-mapping>
</#if>
<#include "persistentclass.hbm.ftl"/>
</hibernate-mapping>
Mine looks like this:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated ${date} by Hibernate Tools ${version} -->
<#if hmgs?exists && hmgs.hasNonDefaultSettings()>
<hibernate-mapping
<#if hmgs.hasDefaultPackage()>
package="${hmgs.defaultPackage}"
</#if>
<#if hmgs.hasSchemaName()>
schema="${hmgs.schemaName}"
</#if>
<#if hmgs.hasCatalogName()>
catalog="${hmgs.catalogName}"
</#if>
<#if hmgs.hasNonDefaultCascade()>
default-cascade="${hmgs.defaultCascade}"
</#if>
<#if hmgs.hasNonDefaultAccess()>
default-access="${hmgs.defaultAccess}"
<#else>
default-access="field"
</#if>
<#if !hmgs.isDefaultLazy()>
default-lazy="false"
</#if>
<#if !hmgs.isAutoImport()>
auto-import="false"
</#if>>
<#else>
<hibernate-mapping default-access="field">
</#if>
<#include "persistentclass.hbm.ftl"/>
</hibernate-mapping>
I added this section:
Code:
<#if hmgs.hasNonDefaultAccess()>
default-access="${hmgs.defaultAccess}"
<#else>
default-access="field"
This is added in the section that inserts various kinds of non-default values. This checks to see if there is already a default-access value set. If so, I honor it. If not, I force default-access to "field".
The other place is this:
Code:
<#else>
<hibernate-mapping default-access="field">
Basically, is just adds the default-access-"field" to the tag when no other non-default values exist.
With this in place and my templatepath correctly set so Hibernate-Tools can find it, may regular old <hbm2hbmxml/> task now generates my own custom mapping files.
For completeness, here is my full hibernatetools task in my ant build.xml file:
Code:
<!-- let ant know about the hibernatetool task -->
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask" />
<!-- pre-compile task to regenrate domain classes and mapping files -->
<target name="-pre-compile">
</target>
<!-- generate the domain classes and mapping files -->
<target name="generate-domain-from-db"
description="run the hibernate task to generate domain classes and mapping files" >
<!-- run the hibernate task to generate domain classes and mapping files -->
<hibernatetool destdir="src" templatepath="src/templates/">
<!-- classpath to hibernate mappings and reveng files -->
<classpath>
<path location="src/tribal/domain"/>
</classpath>
<!--
we are using jdbc to read configuration from database.
we are using a reverse strategy to generate abstract
domain classes. The TribalDomainGeneration project
builds the reverse strategy class. You must build the
project and add the resulting jar (in dist) to the ant
libraries (in the tools/options menu).
-->
<jdbcconfiguration
propertyfile="src/tribal/domain/hibernate.properties"
revengfile="src/tribal/domain/hibernate.reveng.xml"
packagename="tribal.domain"
detectmanytomany="true"
/>
<!-- order of generators is important -->
<!-- we are generating the hbm.xml files -->
<hbm2hbmxml destdir="src"/>
<!-- we are generating the java files -->
<hbm2java jdk5="true" />
<!-- we are generating the hibernate config file -->
<hbm2cfgxml destdir="src/tribal/domain" />
</hibernatetool>
</target>