ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Hibernate Class Generation Using hbm2java
Pages: 1, 2, 3, 4, 5, 6

Placing Code in the Mapping File: The class-code Meta Attribute

For simple methods, you can use the class-code meta attribute to specify additional Java code from within the Hibernate mapping file. For example, suppose we want a bidirectional relation between a country and its airports. Whenever we add an airport to a Country object, we want to be sure to set the reciprocal country attribute in the Airport object. We can do this as follows:

  
    <class name="Country" table="COUNTRY" dynamic-update="true">
        <meta attribute="implement-equals">true</meta>
        <meta attribute="class-code">
            <![CDATA[
                /**
                 * Add an airport to this country
                 */
                public void addAirport(Airport airport) {
                    airport.setCountry(this);
                    if (airports == null) {
                          airports = new java.util.HashSet();
                    }
                    airports.add(airport);
                }

            ]]>
        </meta>


        <id name="id" type="long" unsaved-value="null" >
            <column name="cn_id" not-null="true"/>
            <generator class="increment"/>
        </id>

           <property column="cn_code" name="code" type="string"/>
           <property column="cn_name" name="name" type="string"/>

          <set name="airports" >
            <key column="cn_id"/>
            <one-to-many class="Airport"/>
          </set>
    </class>
  
This approach is not particularly satisfying, except for very small methods: writing Java code in XML files tends to be error-prone and difficult to maintain.

Using SQL Expressions

Sometimes the business logic (especially if it involves aggregations, sums, totals, and so on) may be more naturally defined by an SQL expression:

  
    <property name="orderTotal" type="java.lang.Double"
              formula="(select sum(item.amount)
                        from item
                        where item.order_id = order_id)" />
  

This is an elegant solution in many cases. However, you should be aware that this query will be executed every time the object is loaded from the database, so it may penalize performance.

Using a Base Class

You can also use the generated-class meta attribute to define a base class, which will be generated by hbm2java, leaving you free to place your business logic in a subclass of this generated class. For example, using this technique for the Country class could be done as follows:

  
    <class name="Country" table="COUNTRY" dynamic-update="true">
        <meta attribute="implement-equals">true</meta>
        <meta attribute="generated-class">CountryBase</meta>
        <meta attribute="scope-field">protected</meta>

        <id name="id" type="long" unsaved-value="null" >
            <column name="cn_id" not-null="true"/>
            <generator class="increment"/>
        </id>

           <property column="cn_code" name="code" type="string"/>
           <property column="cn_name" name="name" type="string"/>

          <set name="airports" >
            <key column="cn_id"/>
            <one-to-many class="Airport"/>
          </set>
    </class>
  

hbm2java will generate the CountryBase class, containing all the attributes, getters, setters, etc. described by the mapping file. Then you are free to place your business logic in the derived class called Country, which will be used and instantiated by Hibernate; for example:

  
    public class Country extends CountryBase {
        /**
         * Add an airport to this country
         */
        public void addAirport(Airport airport) {
                airport.setCountry(this);
                if (getAirports() == null) {
                        setAirports(new java.util.HashSet());
                }
                getAirports().add(airport);
        }
    }
  

Wrapper or Delegate Patterns

For more complex business logic, you may also want to use one of the following techniques:

  • You can define a "wrapper" or "delegate" class, which has the domain class as an attribute, and which provides additional business logic for a given domain object.
  • You may prefer a "service" or "facade" approach, where a "facade" object (such as a stateless session EJB) provides a set of related business services that manipulate domain objects.

Conclusion

This article describes one approach we used to manage Hibernate mappings, which worked well in our particular circumstances. There are, of course, many others. Maybe this article will provide some ideas for your projects, but whatever you do, use whatever suits your project best!

Resources

John Ferguson Smart is a freelance consultant specializing in Enterprise Java, Web Development, and Open Source technologies, currently based in Wellington, New Zealand.


Return to ONJava.com.