Extending XDoclet Hibernate Module

As you may know, bag collection type of Hibernate contains its elements unordered and unindexed as well as multiple copies of one element instance in it. Java Collection Framework does not have  a bag concept already, so we utilize available List type to implement bag semantics in Java, although List keeps its elements ordered.

From the performance point of view, using bag as collection value mapping in Hibernate is almost the worst case, because there is no index or primary key column and duplicate elements exist in database. Hibernate has no means to distinguish among those duplicate elements for update, so it resolves this problem first deleting all collection elements, in one delete operation, then inserts all values again.

Hibernate provides one special type of bag element named idbag, which let us define a surrogate primary key/synthetic identifier for each bag element. Hibernate?s idbag mappings are much more performant than their bag counterparts because of the surrogate primary key. By means of that key, hibernate is able to locate and update individual bag elements which are dirty.

Unfortunately, there is no mechanism in XDoclet Hibernate module to define idbag mapping. Hence, we modified and added this feature to define them via XDoclet tags. Hibernate idbag element requires collection-id sub-element to create a surrogate key, therefore we first added following lines into hibernate-collections.xdt file.

<XDtMethod:ifHasMethodTag tagName="hibernate.collection-id">
    <collection-id column="<XDtMethod:methodTagValue tagName="hibernate.collection-id" paramName="column" />"

type="<XDtMethod:methodTagValue tagName="hibernate.collection-id" paramName="type" />"
                                               <XDtMethod:ifHasMethodTag tagName="hibernate.collection-id" paramName="length">
                                                            length="<XDtMethod:methodTagValue tagName="hibernate.collection-id" paramName="length" />"
    <XDtMethod:ifHasMethodTag tagName="hibernate.collection-id" paramName="generator-class">
        <generator class="<XDtMethod:methodTagValue tagName="hibernate.collection-id" paramName="generator-class" />"/>

Our second modification goes into hibernate-properties.xdt file;

<XDtMethod:ifHasMethodTag tagName="hibernate.idbag">
        <XDtMethod:ifHasMethodTag tagName="hibernate.idbag" paramName="table">
        table="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="table" />"

<XDtMethod:ifHasMethodTag tagName="hibernate.idbag" paramName="schema">
    schema="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="schema" />"

    lazy="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="lazy" values="true,false" default="false"/>"
    cascade="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="cascade" values="none,all,save-update,delete,all-delete-orphan,delete-orphan" default="none"/>"
<XDtMethod:ifHasMethodTag tagName="hibernate.idbag" paramName="order-by">
order-by="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="order-by" />"
<XDtMethod:ifHasMethodTag tagName="hibernate.idbag" paramName="where">
    where="<XDtMethod:methodTagValue tagName="hibernate.idbag" paramName="where" />"

And finally we have to add following lines into xtags.xml file, in order to make JBoss IDE XDoclet Code Assist feature to recognize those additions;

    <usage-description>Defines an idbag</usage-description>
    <condition type="method"/>
    <parameter type="text">
        <usage-description>The name of the collection table (not used for one-to-many associations)</usage-description>
    <parameter type="text">
        <usage-description>The name of a table schema to override the schema declared</usage-description>
    <parameter type="bool">
        <usage-description>Enable lazy initialization</usage-description>
    <parameter type="text">   
        <usage-description>Specifies which operations should be cascaded from the parent object to the associated object</usage-description>
    <parameter type="text">
       <usage-description>Specify table columns that define the iteration order</usage-description>
     <parameter type="text">
        <usage-description>An SQL WHERE condition</usage-description>

Here comes a sample java comment in which you can see how idbag collection mapping can be done with newly defined Xdoclet tags. Example tries to create a 1:m relationship between Set-Game. As you already see there is no difference from bag collection mapping, except collection-id.

* @hibernate.idbag table = "GAME" order-by = "GAME_ID asc"
* @hibernate.collection-id column = "GAME_ID" type="integer"
* length="10" generator class="native"
* @hibernate.collection-key column = "FK_SET_ID"
* @hibernate.collection-composite-element class = "model.Game"

Our second modification is for creating m:n relationships, where one side of the m:n relationship?s primary key consists of more than one column. Currently, XDoclet Hibernate module does not support this, and we modified lines for  hibernate.collection-many-to-many tag in hibernate-collections.xdt file as follows;

This modification help us to get following excerpt;

<many-to-many class="model.Module" outer-join="auto">
    <column name="MODULE_CODE" />
    <column name="MODULE_NO" />

And the java comment to generate above output is as follows;

  * @hibernate.list table = "DEVELOPER_MODULE" cascade = "save-update"
  * @hibernate.collection-key column = "FK_DEVELOPER_ID"
  * @hibernate.collection-index column = "ORDER_NO"
  * @hibernate.collection-many-to-many class = "model.Module"

  * @hibernate.column name = "MODULE_CODE"
  * @hibernate.column name = "MODULE_NO"