Hibernate Module

Hibernate is an open-source object/relational mapping tool for accessing relational databases from Java applications. JavaGen allows you to specify your object model in UML and generate high-quality Java source containing Hibernate-specific XDoclet mapping tags.

This guide focuses on JavaGen-specific techniques for transforming UML class diagrams to persistent object models and assumes proficient knowledge of UML, Hibernate, Java and XDoclet. See references for excellent, more general sources on these topics.

Contents:

Simple Example

JavaGen generates Java source code decorated with XDoclet tags:

/**
 * @hibernate.class
 *   table="CUSTOMER"
 *   schema="SALES"
 */
public class Customer
{
  /**
   * @hibernate.id
   *   generator-class="assigned"
   */
  public String getId() { return id; } 
	...

XDoclet is also a primary means of customizing the generated code. You can modify the generated code and mappings by attaching @hibernate XDoclet tags in the UML at the class, attribute or association levels. JavaGen passes through whatever is present in the UML (including source code in method bodies) only generating what is necessary to produce a working Hibernate mapping (see Customization).

Mapping Classes

Marking Persistent Classes

In order to map classes to database tables, JavaGen must know which classes to make persistent. There are two UML stereotypes for achieving this, <<entity>> and <<entity-value-object>> corresponding to the two different ways Hibernate maps classes: entities and components of entities.

<<entity>> Stereotype

Classes marked with the <<entity>> stereotype are mapped to their own tables with their own primary keys. Entities have independent life-cycles and have few restrictions on the types of relations they can form with other entities. Entities must have a unique primary key. If you do not define one, JavaGen will add a private primary key property for you.

Here is a simple entity class (TODO: update the stereotype in this diagram):

UML representation of entity class

which is mapped to a database table that looks something like this:

+-------------------------------------------------------------------+
| customer table                                                    |
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      |      | PRI | NULL    | auto_increment |
| name       | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

<<entity-value-object>> Stereotype

Classes marked with the <<entity-value-object>> stereotype are mapped to value objects by JavaGen. A value object can be persisted as a Hibernate component, but cannot exist in the database independently of its owning entity, nor can it have true relations with other objects.

The following UML diagram illustrates two equivalent representations (Parent1 and Parent2) of a one-to-one relation between an entity and value object (TODO: update the stereotype in this diagram).

Equivelent value object representations in UML Class Diagram

Whichever representation is chosen the results are the same; Hibernate maps all the value object attributes into the entity table roughly as follows:

TODO show SQL table

Value objects can be nested to any level with the only limitation being only one level of one-to-many mapping is allowed (eg one-to-many relation cannot contain a nested one-to-many relation).

Table Names

By default JavaGen does not emit table names. Hibernate provides a more flexible way to achive this using the NamingStrategy interface. To turn on table name generation set:

javagen.hibernate.generate.sql.names="true"

You can set a table name on a specific class with a UML Tagged Value, for example:

@hibernate.class
    table="CAT_TBL"

Inner Classes

(Currently not tested or supported)

Inheritance

JavaGen will try to infer the best mapping based on the UML model. As usual you can override JavaGen by specifying the @hibernate.class, @hibernate.subclass and @hibernate.joined-subclass XDoclet tags as UML tagged values on the class. The three types of inheritance supported by Hibernate are:

InheritanceDescription
Table per subclassThis is the default JavaGen mapping between <<entity>> classes resulting in the joined-subclass Hibernate mapping.
Table per concrete classJavaGen generates this mapping when each concrete class in an entity hierarchy has a @hibernate.class tagged value.
Table per class hierarchyTo specify this mapping define a discriminator name for each UML generalization in the hierarchy. The discriminator name becomes the value placed in the discriminator column defined in the super class. The alternative technique is to explicitly define a @hibernate.subclass tagged value with the discriminator-value attribute assigned to each subclass. You'll also need to specify the @hibernate.discriminator tag and column attribute on the super class.

Mapping Attributes

UML attributes usually correspond to Java fields or properties, which in turn are mapped to columns in the database.

Persistent Properties

JavaGen will map attributes to Java properties, unless they are static, transient or marked with the <<field>> stereotype. JavaGen automatically generates get and set methods for properties unless they are frozen (read-only) or addOnly (write-only). Likewise, if either a get or set property method is found JavaGen will only generate absent XDoclet tags.

Because XDoclet tags are attached to the get method, JavaGen must generate a private getter method for write-only properties to hang the tags on.

Primary Keys

Primary keys are properties that uniquely identify rows in a database. Entity tables must have a primary key, if no key is declared JavaGen, will create a private syntheticId property as a java.lang.Integer.

JavaGen generates primary key mappings based on the following UML stereotypes:

StereotypeDescription
<<synthetic-key>>Synthetic keys are generated by the database and must be integer types: (short, int, long, java.lang.Short, java.lang.Integer or java.lang.Long). By default JavaGen emits:
@hibernate.id
    generator-class="native"
The native value delegates the key generation decision to Hibernate which in turn picks identity, sequence or hilo based on the selected database. This setting reportedly does not work well with some databases. It can be specified per-class using XDoclet tags or globally using the following property:
javagen.hibernate.default.generator.class="hilo"
By default Hibernate looks for null primary key values to determine weather an object is new or not (i.e. when making sql insert or update decisions). If you use primitive types for primary keys (int or long) additional configuration is required for Hibernate to function properly. Therefore, we recommend you use non-primitive types (either java.lang.String or primitive wrappers) to avoid these issues.
<<primary-key>>This primary key type is often called a natural key (think social security number) and must be supplied by the user or application. JavaGen emits the following for this stereotype:
@hibernate.id
    generator-class="assigned"
<<business-key>>Not a real primary key from the database point of view, JavaGen includes properties with this stereotype when overriding the equals and hashCode methods. This is necessary in situation where new entities (who's primary key are null) are in a mixed collection. In such cases so-called business keys must be used to establish equality and this stereotype helps JavaGen streamline the implementation of these two methods.

Constrained Foreign Key Generators

For one-to-one primary key type relations (i.e. when no foreign key is involved) JavaGen emits the foreign generator type (see constrained relations).

Primary Key Customization

Finally you can override the type of primary key emitted by attaching an XDoclet attribute to the property as a UML Tagged Value. For example:

@hibernate.id
    generator-class="identity"

Attribute Modeling Best Practices

Don't use attributes to represent associationsUML attributes should map to simple Java types; in other words Java value types that have a Hibernate mapping type defined. Java collection types (Collection, Set, Map, List, etc.) should always be specified using associations. (How else are you going to specify what type the collection contains?) Likewise, JavaGen will complain if you define an attribute using an <<entity>> type because this is really a one-to-one association.
Transient and static attributes are not persistedFollowing Java semantics, transient associations are not stored in the database. Nor does it make sense to store static attributes.
Avoid Java ArraysJavaGen supports one-dimensional arrays of simple types, but you get better performance and more control if you model arrays as associations.

Composition

Fine-grained modeling is encouraged in Hibernate and you may nest POJOs (plain old Java objects) as deep as you wish with the only restriction being composition collections cannot contain nested collections. The nested POJO attributes are mapped using composition (i.e. by flattening the object tree into a single table).

Column Names

By default JavaGen does not emit column names. Hibernate provides a more flexible way to achive this using the NamingStrategy interface.

To have JavaGen generate column names set the following property in you build:

javagen.hibernate.generate.sql.names="true"

You can specify a column name on a specific attribute by attaching either of the following XDoclet tags:

@hibernate.property
    column="FIRST_NAME"

or

@hibernate.column
    name="FIRST_NAME"

TODO: explain the duplication above.

<<order-by-asc>> and <<order-by-desc>> Stereotypes

Labeling a property with the <<order-by-asc>> or <<order-by-desc>> stereotypes results in the order-by="column_name asc|desc" Hibernate mapping and Java collection types that behave like LinkedHashMap, LinkedHashSet and LinkedHashList.

If the SQL column name is not the same as the property name you need to specify this mapping using XDoclet tags, for example:

@hibernate.set
    order-by="purchase_date desc"

Not Null

Primary keys are always mapped as not-null="true". You can specify this on non-key properties by setting the multiplicity to '1'. By default nulls are allowed which corresponds to a multiplicity of 0..1 (or no value in Poseidon).

Mapping Associations

UML Associations should generally be used between <<entity>> classes (i.e. classes that have primary keys). Associations can be one-to-one, one-to-many, many-to-one or many-to-many. In most cases JavaGen will generate an appropriate mapping, but you can customize the results by attaching XDoclet tags on the association ends as UML Tagged Value pairs.

Naming Association Ends

It is good practice to name your association ends, as this results in higher quality generated code with more meaningful property, method, column and table names. If no name is found on an association end JavaGen uses the class name - which works most of the time. However, in situations were you have multiple relations between the same two entities or relations to a single entity (i.e. self referential relations) you will encounter naming conflicts if you do not assign unique names to the association ends.

Optionally, you can use singular or plural names to reflect the cardinality (one or many) of the relation end.

Limitations

JavaGen does not support association classes. It is easy to work around this limitation by making the association class an entity and using two one-to-many associations for either side. Because JavaGen achieves its Hibernate mapping using XDoclet tags, any limitations in XDoclet limit JavaGen's capabilities (NEED SPECIFICS).

One-to-One Associations

There are two categories of one-to-one associations:

KeyDescription
Foreign KeyThis is the default one-to-one mapping and is between a foreign key in one table and a primary key in the other. JavaGen picks the foreign key end based on visibility and efficiency constraints. To explicitly specify foreign key placement, attach the following XDoclet tag to the desired association end:
@hibernate.many-to-one
    foreign-key="MY_FK"
Note: Only the @hibernate.many-to-one tag is significant to JavaGen, the attribute can be anything - noop='ignore' would work as well.
Primary KeyThese are relations in which the primary keys have the same value and are specified using a constrained relation end. To specify this in JavaGen add the following XDoclet tag to the constrained association end:
@hibernate.one-to-one
    constrained="true"
JavaGen will automatically add the foreign key generator tags to the primary key of the subjugate class.

One-to-Many Associations

One-to-many associations are generated true to their UML representation:

  • java.util.Set is the default container for unordered association ends and java.util.List is used for ordered association ends. Other container types can be specified using XDoclet tags.
  • A UML composition will generate parent/child relation with cascading update and delete behavior.
  • Unidirectional and bidirectional relations are set with the navigable setting.
  • Many ends with * cardinality generate NULLABLE foreign key mappings whereas 1..* ends generate NOT-NULL foreign key mappings.

Many-to-Many Associations

Many-to-many associations result in a third association table being generated, otherwise they are similar to one-to-many associations. If you need more control over the mapping details, many-to-many associations can be modeled as two one-to-many associations with a common association class in the middle.

Java Collection Types

JavaGen will generate the appropriate Java collection class based on the UML settings specified. Other collection types can be specified using XDoclet tags.

ClassDescription
java.lang.Set java.lang.Set is the default class generated for many ended unordered associations. Hibernate limits the members to non-null values.
java.lang.ListThe List interface is generated for ordered many ended UML associations. An index column (@hibernate.collection-index) is generated to maintain list order.
BagThere is no way to specify bag semantics in UML (at least in a standard way) so you must place the @hibernate.bag XDoclet attribute on the correct association end.

At the time of this writting idbag is not supported by XDoclet 1.2.2. The work-around is to use a @hibernate.bag tag and replace it with idbag in a post-XDoclet XSLT transformation (see XSLT Descriptor Processing).

java.lang.MapUse the @hibernate.map XDcolet tag or parameterized associations.
Java arraysYou must place @hibernate.array or @hibernate.primitive-array XDcolet tags in your UML to generate an arrays in JavaGen.

Limitations

JavaGen is best used when generating database schemas form object models verses working backwards from the database schema. If your working with an existing database, you'll want to convert the database schema to UML before proceeding or use an alternate tool such as MiddelGen (see Tools for Hibernate).

XDoclet imposes a few limitations on some of Hibernate's more exotic mapping types, however one can usually achieve the desired result using other techniques. An XSLT template is provided in the JAM build to correct a few minor bugs with XDoclet and more importantly can serve as the basis for custimizing your mapping files.

Currently only XDoclet 1.2.2 is supported. The Hibernate module in XDoclet 2.0 uses slightly different tag names and is not supported for the time being. A persuasive request from a loyal user could change this ;-)

JavaGen Stereotypes

StereotypeUML ElementDescription
<<entity>> Class Generates a Hibernate entity mapping. See entity
<<entity-value-object>> Class Generates a Hibernate component mapping. See entity-value-object
<<synthetic-key>> Attribute Generates a auto-increment primary key mapping. See synthetic-key
<<primary-key>> Attribute Generates a primary key mapping. See primary-key
<<business-key>> Attribute Generates a special equals and hashCode methods. See business-key
<<order-by-desc>> Attribute Generates a order-by="column_name desc" mapping. See order-by-desc
<<order-by-asc>> Attribute Generates a order-by="column_name asc" mapping. See order-by-asc

JavaGen Ant Properties

Set these properties in your build.xml or props-javagen.xml file:

PropertyDefaultDescription
javagen.hibernate.flag false Switch that turns on hibernate module, set to true to activate.
javagen.hibernate.generate.sql.names false Set to true to have JavaGen generate table and column names.
javagen.hibernate.default.generator.class native Specifies the default generator class to use.
javagen.hibernate.version 2 Specifies the Hibernate version to generate for. Valid values are 2 or 3.


Appendix A - References

  • Hibernate includes one of the best open-source reference documents I've seen.
  • For a more organized resource try Hibernate in Action.
  • For a complete list of available @hibernate tags the only source is the documentation that is bundled with XDoclet.
  • One of the few books dedicated to XDoclet is Manning's XDoclet in Action.

Appendix B - Hibernate 3.x Support

Due to a few API changes Hibernate 3.x is not compatible with Hibernate 2.x code. By setting

<property name="javagen.hibernate.version" value="3"/>

JavaGen will generate Hibernate 3.x compatible Java source code.

Alternatively, you can develop in 2.x and upgrade to 3.x latter. Upgrading is trivial because JavaGen generated entity classes work without change and non-entity DAO (Data Access Objects) classes only require the following changes:

  • Renaming packages from net.sf.hibernate to org.hibernate and net.sf.hibernate.expression with org.hibernate.criterion.
  • Replacing session.delete("FROM Orders") statements with session.createQuery("DELETE FROM Orders").executeUpate().
  • Removing HibernateException from method signatures.
  • Replacing FetchMode.LAZY and FetchMode.EAGER with FetchMode.SELECT and FetchMode.JOIN.

Upgrading Metadata to 3.x using XSLT

As a temporary measure, JAM provides a XSLT stylesheet that updates mapping files generated by XDoclet from Hibernate 2.x to 3.x. To activate this transformation set the following property in your build.xml file:

<property name="hibernate.mapping.stylesheet" location="${jam.home}/xsl/hibernate3Upgrade.xsl"/>

If you're not using JAM, you can obtain the above stylesheet for JAM's CVS repository.

Appendix C - Terminology

UML, Java, XDoclet and relational databases all have their own terminology for describing overlapping concepts or in some cases the same word for different concepts. The most confusing term is attribute which is used in UML to describe a field or property and in XDoclet to describe a meta-data key/value pair. We use the term both ways depending on the context.

UML terms are also unfamiliar to many people. Common UML terms and how they relate to Java and database concepts are as follows:

UMLJavaDatabase
Classclasstable
Attributeproperty/fieldcolumn
Associationreferencerelation
One-to-one Associationone-to-one reference/pointerone-to-one relation
One-to-many associationcollection/arrayone-to-many relation
Generalizationinheritance(no equivalent)
Abstractionimplementation(no equivalent)
Association End/Rolereference (get/set methods)relation name
Compositionlife cycle dependencycascading deletes
Aggregation??
Navigablepublic accessorsreference navigation
1 Multiplicityrequired fieldNOT NULL
0..1 multiplicityoptional fieldNULLABLE
Changeabilityread-write access?
<<Entity>>persistent objecttable with primary key
transienttransientno column defined

Finally Hibernate has its own terms of which some of the more confusing are:

  • association - Generally refers to relations between true entities (objects with a primary key).
  • many-to-one - A more descriptive name for this mapping term would have been foreign-key-association because it maps a relation with a foreign key. It is actually used to map both one-to-one and many-to-one relations!
  • value objects - TODO
  • components - TODO
  • composition - TODO