Chapter 16. Toolset Guide

Roundtrip engineering with NHibernate is possible using a set of commandline tools maintained as part of the NHibernate project, along with NHibernate support built into various code generation tools (MyGeneration, CodeSmith, ObjectMapper, AndroMDA).

The NHibernate main package comes bundled with the most important tool (it can even be used from "inside" NHibernate on-the-fly):

Other tools directly provided by the NHibernate project are delivered with a separate package, NHibernateContrib. This package includes tools for the following tasks:

Third party tools with NHibernate support are:

These 3rd party tools are not documented in this reference. Please refer to the NHibernate website for up-to-date information.

16.1. Schema Generation

The generated schema includes referential integrity constraints (primary and foreign keys) for entity and collection tables. Tables and sequences are also created for mapped identifier generators.

You must specify a SQL Dialect via the hibernate.dialect property when using this tool.

16.1.1. Customizing the schema

Many NHibernate mapping elements define an optional attribute named length. You may set the length of a column with this attribute. (Or, for numeric/decimal data types, the precision.)

Some tags also accept a not-null attribute (for generating a NOT NULL constraint on table columns) and a unique attribute (for generating UNIQUE constraint on table columns).

Some tags accept an index attribute for specifying the name of an index for that column. A unique-key attribute can be used to group columns in a single unit key constraint. Currently, the specified value of the unique-key attribute is not used to name the constraint, only to group the columns in the mapping file.

Examples:

<property name="Foo" type="String" length="64" not-null="true"/>

<many-to-one name="Bar" foreign-key="fk_foo_bar" not-null="true"/>

<element column="serial_number" type="Int64" not-null="true" unique="true"/>

Alternatively, these elements also accept a child <column> element. This is particularly useful for multi-column types:

<property name="Foo" type="String">
    <column name="foo" length="64" not-null="true" sql-type="text"/>
</property>

<property name="Bar" type="My.CustomTypes.MultiColumnType, My.CustomTypes"/>
    <column name="fee" not-null="true" index="bar_idx"/>
    <column name="fi" not-null="true" index="bar_idx"/>
    <column name="fo" not-null="true" index="bar_idx"/>
</property>

The sql-type attribute allows the user to override the default mapping of NHibernate type to SQL datatype.

The check attribute allows you to specify a check constraint.

<property name="Foo" type="Int32">
    <column name="foo" check="foo > 10"/>
</property>

<class name="Foo" table="foos" check="bar < 100.0">
    ...
    <property name="Bar" type="Single"/>
</class>

Table 16.1. Summary

AttributeValuesInterpretation
lengthnumbercolumn length/decimal precision
not-nulltrue|falsespecfies that the column should be non-nullable
uniquetrue|falsespecifies that the column should have a unique constraint
indexindex_namespecifies the name of a (multi-column) index
unique-keyunique_key_namespecifies the name of a multi-column unique constraint
foreign-keyforeign_key_name specifies the name of the foreign key constraint generated for an association, use it on <one-to-one>, <many-to-one>, <key>, and <many-to-many> mapping elements. Note that inverse="true" sides will not be considered by SchemaExport.
sql-typecolumn_type overrides the default column type (attribute of <column> element only)
checkSQL expression create an SQL check constraint on either column or table

16.1.2. Running the tool

The SchemaExport tool writes a DDL script to standard out and/or executes the DDL statements.

java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2ddl.SchemaExport options mapping_files

Table 16.2. SchemaExport Command Line Options

OptionDescription
--quietdon't output the script to stdout
--droponly drop the tables
--textdon't export to the database
--output=my_schema.ddloutput the ddl script to a file
--config=hibernate.cfg.xmlread Hibernate configuration from an XML file
--properties=hibernate.propertiesread database properties from a file
--formatformat the generated SQL nicely in the script
--delimiter=xset an end of line delimiter for the script

You may even embed SchemaExport in your application:

Configuration cfg = ....;
new SchemaExport(cfg).create(false, true);

16.1.3. Properties

Database properties may be specified

  • as system properties with -D<property>

  • in hibernate.properties

  • in a named properties file with --properties

The needed properties are:

Table 16.3. SchemaExport Connection Properties

Property NameDescription
hibernate.connection.driver_classjdbc driver class
hibernate.connection.urljdbc url
hibernate.connection.usernamedatabase user
hibernate.connection.passworduser password
hibernate.dialectdialect

16.1.4. Using Ant

You can call SchemaExport from your Ant build script:

<target name="schemaexport">
    <taskdef name="schemaexport"
        classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
        classpathref="class.path"/>
    
    <schemaexport
        properties="hibernate.properties"
        quiet="no"
        text="no"
        drop="no"
        delimiter=";"
        output="schema-export.sql">
        <fileset dir="src">
            <include name="**/*.hbm.xml"/>
        </fileset>
    </schemaexport>
</target>

If you don't specify properties or a config file, the SchemaExportTask will try to use normal Ant project properties instead. In other words, if you don't want or need an external configuration or properties file, you may put hibernate.* configuration properties in your build.xml or build.properties.

16.1.5. Incremental schema updates

The SchemaUpdate tool will update an existing schema with "incremental" changes. Note that SchemaUpdate depends heavily upon the JDBC metadata API, so it will not work with all JDBC drivers.

java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2ddl.SchemaUpdate options mapping_files

Table 16.4. SchemaUpdate Command Line Options

OptionDescription
--quietdon't output the script to stdout
--properties=hibernate.propertiesread database properties from a file

You may embed SchemaUpdate in your application:

Configuration cfg = ....;
new SchemaUpdate(cfg).execute(false);

16.1.6. Using Ant for incremental schema updates

You can call SchemaUpdate from the Ant script:

<target name="schemaupdate">
    <taskdef name="schemaupdate"
        classname="net.sf.hibernate.tool.hbm2ddl.SchemaUpdateTask"
        classpathref="class.path"/>
    
    <schemaupdate
        properties="hibernate.properties"
        quiet="no">
        <fileset dir="src">
            <include name="**/*.hbm.xml"/>
        </fileset>
    </schemaupdate>
</target>

16.2. Code Generation

The Hibernate code generator may be used to generate skeletal Java implementation classes from a Hibernate mapping file. This tool is included in the Hibernate Extensions package (a seperate download).

hbm2java parses the mapping files and generates fully working Java source files from these. Thus with hbm2java one could "just" provide the .hbm files, and then don't worry about hand-writing/coding the Java files.

java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2java.CodeGenerator options mapping_files

Table 16.5. Code Generator Command Line Options

OptionDescription
--output=output_dirroot directory for generated code
--config=config_fileoptional file for configuring hbm2java

16.2.1. The config file (optional)

The config file provides for a way to specify multiple "renderers" for the source code and to declare <meta> attributes that is "global" in scope. See more about this in the <meta> attribute section.

<codegen>
    <meta attribute="implements">codegen.test.IAuditable</meta>
    <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/>
    <generate
        package="autofinders.only"
        suffix="Finder"
        renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/>
</codegen>

This config file declares a global meta attribute "implements" and specify two renderers, the default one (BasicRenderer) and a renderer that generates Finder's (See more in "Basic Finder generation" below).

The second renderer is provided with a package and suffix attribute.

The package attribute specifies that the generated source files from this renderer should be placed here instead of the package scope specified in the .hbm files.

The suffix attribute specifies the suffix for generated files. E.g. here a file named Foo.java would be FooFinder.java instead.

It is also possible to send down arbitrary parameters to the renders by adding <param> attributes to the <generate> elements.

hbm2java currently has support for one such parameter, namely generate-concrete-empty-classes which informs the BasicRenderer to only generate empty concrete classes that extends a base class for all your classes. The following config.xml example illustrate this feature

            <codegen>
              <generate prefix="Base" renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/> 
              <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer">
                <param name="generate-concrete-empty-classes">true</param>
                <param name="baseclass-prefix">Base</param>
              </generate>
            </codegen>

Notice that this config.xml configure 2 (two) renderers. One that generates the Base classes, and a second one that just generates empty concrete classes.

16.2.2. The meta attribute

The <meta> tag is a simple way of annotating the hbm.xml with information, so tools have a natural place to store/read information that is not directly related to the Hibernate core.

You can use the <meta> tag to tell hbm2java to only generate "protected" setters, have classes always implement a certain set of interfaces or even have them extend a certain base class and even more.

The following example:

<class name="Person">
    <meta attribute="class-description">
        Javadoc for the Person class
        @author Frodo
    </meta>
    <meta attribute="implements">IAuditable</meta>
    <id name="id" type="long">
        <meta attribute="scope-set">protected</meta>
        <generator class="increment"/>
    </id>
    <property name="name" type="string">
        <meta attribute="field-description">The name of the person</meta>
    </property>
</class>

will produce something like the following (code shortened for better understanding). Notice the Javadoc comment and the protected set methods:

// default package

import java.io.Serializable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/** 
 *         Javadoc for the Person class
 *         @author Frodo
 *     
 */
public class Person implements Serializable, IAuditable {

    /** identifier field */
    public Long id;

    /** nullable persistent field */
    public String name;

    /** full constructor */
    public Person(java.lang.String name) {
        this.name = name;
    }

    /** default constructor */
    public Person() {
    }

    public java.lang.Long getId() {
        return this.id;
    }

    protected void setId(java.lang.Long id) {
        this.id = id;
    }

    /** 
     * The name of the person
     */
    public java.lang.String getName() {
        return this.name;
    }

    public void setName(java.lang.String name) {
        this.name = name;
    }

}

Table 16.6. Supported meta tags

AttributeDescription
class-descriptioninserted into the javadoc for classes
field-descriptioninserted into the javadoc for fields/properties
interfaceIf true an interface is generated instead of an class.
implementsinterface the class should implement
extendsclass the class should extend (ignored for subclasses)
generated-classoverrule the name of the actual class generated
scope-classscope for class
scope-setscope for setter method
scope-getscope for getter method
scope-fieldscope for actual field
use-in-tostringinclude this property in the toString()
implement-equalsinclude a equals() and hashCode() method in this class.
use-in-equalsinclude this property in the equals() and hashCode() method.
boundadd propertyChangeListener support for a property
constrainedbound + vetoChangeListener support for a property
gen-propertyproperty will not be generated if false (use with care)
property-typeOverrides the default type of property. Use this with any tag's to specify the concrete type instead of just Object.
class-codeExtra code that will inserted at the end of the class
extra-importExtra import that will inserted at the end of all other imports
finder-methodsee "Basic finder generator" below
session-methodsee "Basic finder generator" below

Attributes declared via the <meta> tag are per default "inherited" inside an hbm.xml file.

What does that mean? It means that if you e.g want to have all your classes implement IAuditable then you just add an <meta attribute="implements">IAuditable</meta> in the top of the hbm.xml file, just after <hibernate-mapping>. Now all classes defined in that hbm.xml file will implement IAuditable! (Except if a class also has an "implements" meta attribute, because local specified meta tags always overrules/replaces any inherited meta tags).

Note: This applies to all <meta>-tags. Thus it can also e.g. be used to specify that all fields should be declare protected, instead of the default private. This is done by adding <meta attribute="scope-field">protected</meta> at e.g. just under the <class> tag and all fields of that class will be protected.

To avoid having a <meta>-tag inherited then you can simply specify inherit="false" for the attribute, e.g. <meta attribute="scope-class" inherit="false">public abstract</meta> will restrict the "class-scope" to the current class, not the subclasses.

16.2.3. Basic finder generator

It is now possible to have hbm2java generate basic finders for Hibernate properties. This requires two things in the hbm.xml files.

The first is an indication of which fields you want to generate finders for. You indicate that with a meta block inside a property tag such as:

<property name="name" column="name" type="string">
     <meta attribute="finder-method">findByName</meta>
</property>

The finder method name will be the text enclosed in the meta tags.

The second is to create a config file for hbm2java of the format:

<codegen>
    <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/>
    <generate suffix="Finder" renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/>
</codegen>

And then use the param to hbm2java --config=xxx.xml where xxx.xml is the config file you just created.

An optional parameter is meta tag at the class level of the format:

<meta attribute="session-method">
    com.whatever.SessionTable.getSessionTable().getSession();
</meta>

Which would be the way in which you get sessions if you use the Thread Local Session pattern (documented in the Design Patterns area of the Hibernate website).

16.2.4. Velocity based renderer/generator

It is now possible to use velocity as an alternative rendering mechanism. The follwing config.xml shows how to configure hbm2java to use its velocity renderer.

    <codegen>
     <generate renderer="net.sf.hibernate.tool.hbm2java.VelocityRenderer">
      <param name="template">pojo.vm</param>
     </generate>
    </codegen>

The parameter named template is a resource path to the velocity macro file you want to use. This file must be available via the classpath for hbm2java. Thus remember to add the directory where pojo.vm is located to your ant task or shell script. (The default location is ./tools/src/velocity)

Be aware that the current pojo.vm generates only the most basic parts of the java beans. It is not as complete and feature rich as the default renderer - primarily a lot of the meta tags are not supported.

16.3. Mapping File Generation

A skeletal mapping file may be generated from compiled persistent classes using a command line utility called MapGenerator. This utility is part of the Hibernate Extensions package.

The Hibernate mapping generator provides a mechanism to produce mappings from compiled classes. It uses Java reflection to find properties and uses heuristics to guess an appropriate mapping from the property type. The generated mapping is intended to be a starting point only. There is no way to produce a full Hibernate mapping without extra input from the user. However, the tool does take away some of the repetitive "grunt" work involved in producing a mapping.

Classes are added to the mapping one at a time. The tool will reject classes that it judges are are not Hibernate persistable.

To be Hibernate persistable a class

  • must not be a primitive type

  • must not be an array

  • must not be an interface

  • must not be a nested class

  • must have a default (zero argument) constructor.

Note that interfaces and nested classes actually are persistable by Hibernate, but this would not usually be intended by the user.

MapGenerator will climb the superclass chain of all added classes attempting to add as many Hibernate persistable superclasses as possible to the same database table. The search stops as soon as a property is found that has a name appearing on a list of candidate UID names.

The default list of candidate UID property names is: uid, UID, id, ID, key, KEY, pk, PK.

Properties are discovered when there are two methods in the class, a setter and a getter, where the type of the setter's single argument is the same as the return type of the zero argument getter, and the setter returns void. Furthermore, the setter's name must start with the string set and either the getter's name starts with get or the getter's name starts with is and the type of the property is boolean. In either case, the remainder of their names must match. This matching portion is the name of the property, except that the initial character of the property name is made lower case if the second letter is lower case.

The rules for determining the database type of each property are as follows:

  1. If the Java type is Hibernate.basic(), then the property is a simple column of that type.

  2. For hibernate.type.Type custom types and PersistentEnum a simple column is used as well.

  3. If the property type is an array, then a Hibernate array is used, and MapGenerator attempts to reflect on the array element type.

  4. If the property has type java.util.List, java.util.Map, or java.util.Set, then the corresponding Hibernate types are used, but MapGenerator cannot further process the insides of these types.

  5. If the property's type is any other class, MapGenerator defers the decision on the database representation until all classes have been processed. At this point, if the class was discovered through the superclass search described above, then the property is an many-to-one association. If the class has any properties, then it is a component. Otherwise it is serializable, or not persistable.

16.3.1. Running the tool

The tool writes XML mappings to standard out and/or to a file.

When invoking the tool you must place your compiled classes on the classpath.

java -cp hibernate_and_your_class_classpaths net.sf.hibernate.tool.class2hbm.MapGenerator options and classnames

There are two modes of operation: command line or interactive.

The interactive mode is selected by providing the single command line argument --interact. This mode provides a prompt response console. Using it you can set the UID property name for each class using the uid=XXX command where XXX is the UID property name. Other command alternatives are simply a fully qualified class name, or the command done which emits the XML and terminates.

In command line mode the arguments are the options below interspersed with fully qualified class names of the classes to be processed. Most of the options are meant to be used multiple times; each use affects subsequently added classes.

Table 16.7. MapGenerator Command Line Options

OptionDescription
--quietdon't output the O-R Mapping to stdout
--setUID=uidset the list of candidate UIDs to the singleton uid
--addUID=uidadd uid to the front of the list of candidate UIDs
--select=modemode use select mode mode(e.g., distinct or all) for subsequently added classes
--depth=<small-int>limit the depth of component data recursion for subsequently added classes
--output=my_mapping.xmloutput the O-R Mapping to a file
full.class.Nameadd the class to the mapping
--abstract=full.class.Namesee below

The abstract switch directs the map generator tool to ignore specific super classes so that classes with common inheritance are not mapped to one large table. For instance, consider these class hierarchies:

Animal-->Mammal-->Human

Animal-->Mammal-->Marsupial-->Kangaroo

If the --abstractswitch is not used, all classes will be mapped as subclasses of Animal, resulting in one large table containing all the properties of all the classes plus a discriminator column to indicate which subclass is actually stored. If Mammal is marked as abstract, Human and Marsupial will be mapped to separate <class> declarations and stored in separate tables. Kangaroo will still be a subclass of Marsupial unless Marsupial is also marked as abstract.