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.