JBoss.orgCommunity Documentation

Chapter 6. Controlling reverse engineering

6.1. Default reverse engineering strategy
6.2. hibernate.reveng.xml file
6.2.1. Schema Selection (<schema-selection>)
6.2.2. Type mappings (<type-mapping>)
6.2.3. Table filters (<table-filter>)
6.2.4. Specific table configuration (<table>)
6.3. Custom strategy
6.4. Custom Database Metadata

When using the <jdbcconfiguration> tag, the Ant task will read the database metadata and then reverse engineer the database schema into a normal Hibernate Configuration. It is from this object (e.g. <hbm2java>) that other artifacts, such as .java and .hbm.xml, can be generated.

To govern this process Hibernate™ uses a reverse engineering strategy. A reverse engineering strategy is mainly called to provide more Java like names for tables, column and foreign keys into classes, properties and associations. It is also used to provide mappings from SQL types to Hibernate™ types.

The strategy can be customized by the user. This can be done by providing a custom reverse engineering strategy should the default strategy does not include the required functionality, or simply define a small component of the strategy and delegate the rest to the default strategy.

Further in this chapter we will discuss how you can configure the process of reverse engineering, what the default reverse engineering strategy includes, as well as some custom concepts.

The default strategy uses a collection of rules for mapping JDBC artifact names to Java artifact names. It also provide basic type mappings from JDBC types to Hibernate™ types. It is the default strategy that uses the packagename attribute to convert a table name into a fully qualified class name.

A hibernate.reveng.xml file can provide a finer degree of control of the reverse engineering process. In this file you can specify type mappings and table filtering. This file can be created by hand (it's just basic XML) or you can use the Section 4.9, “Reveng.xml Editor”, which provides a specialized editor.

Note:

Many databases have case-sensitive names, so if a table does not match, and you are sure it is not excluded by a <table-filter>, check that the case matches. Most databases stores table names in upper case.

Below you can see an example of a reveng.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering 
  SYSTEM "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd" >

<hibernate-reverse-engineering>

<type-mapping>
 <!-- jdbc-type is name for java.sql.Types -->
 <sql-type jdbc-type="VARCHAR" length='20' hibernate-type="SomeUserType" /> 
 <sql-type jdbc-type="VARCHAR" length='1' hibernate-type="yes_no" />
 <!-- length, scale and precision can be used to specify the mapping precisely -->
 <sql-type jdbc-type="NUMERIC"  precision='1' hibernate-type="boolean" /> 
 <!-- the type-mappings are ordered. This mapping will be consulted last, 
  thus overridden by the previous one if precision=1 for the column -->
 <sql-type jdbc-type="NUMERIC"  hibernate-type="long" /> 
</type-mapping>

<!-- BIN$ is recycle bin tables in Oracle -->
<table-filter match-name="BIN$.*" exclude="true" /> 

<!-- Exclude DoNotWantIt from all catalogs/schemas -->
<table-filter match-name="DoNotWantIt" exclude="true" /> 

<!-- exclude all tables from the schema SCHEMA in catalog BAD. -->
<table-filter match-catalog="BAD" match-schema="SCHEMA" match-name=".*" exclude="true" /> 

<!-- table allows you to override/define how reverse engineering 
     is done for a specific table -->
<table name="ORDERS"> 
 <primary-key>
   <!-- setting up a specific id generator for a table -->
  <generator class="sequence">
    <param name="table">seq_table</param>
  </generator>
   <key-column name="CUSTID"/>
 </primary-key>
 <column name="NAME" property="orderName" type="string" />
 <!-- control many-to-one and set names for a specific named foreign key constraint -->
 <foreign-key constraint-name="ORDER_CUST">
   <many-to-one property="customer"/>
   <set property="orders"/>
 </foreign-key>
 <!-- can also control a pure (shared pk) one-to-one  -->
  <foreign-key constraint-name="ADDRESS_PERSON">
   <one-to-one exclude="false"/>
   <inverse-one-to-one exclude="true"/>
  </foreign-key>
</table>

</hibernate-reverse-engineering>

The <type-mapping> section specifies how the JDBC types found in the database should be mapped to Hibernate types. e.g. java.sql.Types.VARCHAR with a length of 1 should be mapped to the Hibernate type yes_no, or java.sql.Types.NUMERIC should generally just be converted to the Hibernate type long.

<type-mapping>
 <sql-type
  jdbc-type="integer value or name from java.sql.Types"
  length="a numeric value"
  precision="a numeric value"
  scale="a numeric value"
  not-null="true|false"  
  hibernate-type="hibernate type name"  
 />
</type-mapping>

The number of attributes specified and the sequence of the sql-type tags are important. This is because Hibernate™ will search for the most specific first, and if no specific match is found it will seek from top to bottom when trying to resolve a type mapping.

The following is an example of a type-mapping which shows the flexibility and importance of the ordering of the type mappings.

<type-mapping>
 <sql-type jdbc-type="NUMERIC" precision="15" hibernate-type="big_decimal"/>
 <sql-type jdbc-type="NUMERIC" not-null="true" hibernate-type="long" />
 <sql-type jdbc-type="NUMERIC" not-null="false" hibernate-type="java.lang.Long" />
 <sql-type jdbc-type="VARCHAR" length="1" not-null="true" 
       hibernate-type="java.lang.Character"/>
 <sql-type jdbc-type="VARCHAR" hibernate-type="your.package.TrimStringUserType"/>
 <sql-type jdbc-type="VARCHAR" length="1" hibernate-type="char"/>
 <sql-type jdbc-type="VARCHAR" hibernate-type="string"/>
</type-mapping>

The following table shows how this affects an example table named CUSTOMER:


The <table> tag allows you to explicitly define how a table should be reverse engineered. It allows control over the naming of a class for the table, provides a way to specify which identifier generator should be used for the primary key and more.

<table 
 catalog="catalog_name"
 schema="schema_name"
 name="table_name"
 class="ClassName"
>
 <primary-key.../>
 <column.../>
 <foreign-key.../>
 </table>

The <foreign-key> tag has two purposes. The first is to define foreign-keys in databases that does not support them or do not have them defined in their schema. The second is to define the name of the resulting properties (many-to-one, one-to-one and one-to-many's).

<foreign-key
  constraint-name="foreignKeyName"
  foreign-catalog="catalogName"
  foreign-schema="schemaName"
  foreign-table="tableName"
 >
 <column-ref local-column="columnName" foreign-column="foreignColumnName"/>
 <many-to-one 
   property="aPropertyName"
   exclude="true|false"/>
 <set 
   property="aCollectionName"
   exclude="true|false"
   
 <one-to-one 
   property="aPropertyName"
   exclude="true|false"/>
 <inverse-one-to-one
   property="aPropertyName"
   exclude="true|false"/>
   </foreign-key>

Table 6.6. Foreign-key attributes

Attribute nameDefinitionAttribute use

constraint-name

Name of the foreign key constraint. Important when naming many-to-one, one-to-one and set. It is the constraint-name that is used to link the processed foreign-keys with the resulting property names.

Required

foreign-catalog

Name of the foreign table's catalog. (Only relevant if you want to explicitly define a foreign key).

Optional

foreign-schema

Name of the foreign table's schema. (Only relevant if you want to explicitly define a foreign key).

Optional

foreign-table

Name of the foreign table. (Only relevant if you want to explicitly define a foreign key).

Optional

column-ref

Defines the foreign-key constraint between a local-column and foreign-column name. (Only relevant if you want to explicitly define a foreign key).

Optional

many-to-one

Defines that a many-to-one should be created and the property attribute specifies the name of the resulting property. Exclude can be used to explicitly define that it should be created or not.

Optional

set

Defines that a set should be created based on this foreign-key and the property attribute specifies the name of the resulting (set) property. Exclude can be used to explicitly define that it should be created or not.

Optional

one-to-one

Defines that a one-to-one should be created and the property attribute specifies the name of the resulting property. Exclude can be used to explicitly define that it should be created or not.

Optional

inverse-one-to-one

Defines that an inverse one-to-one should be created based on this foreign-key and the property attribute specifies the name of the resulting property. Exclude can be used to explicitly define that it should be created or not.

Optional


It is possible to implement a user strategy. Such a strategy must implement org.hibernate.cfg.reveng.ReverseEngineeringStrategy. It is recommended that you use the DelegatingReverseEngineeringStrategy and provide a public constructor which takes another ReverseEngineeringStrategy as an argument. This will allow you to only implement the relevant methods and provide a fall back strategy. An example is shown below of a custom delegating strategy that converts all column names ending with "PK" into a property named "id".

public class ExampleStrategy extends DelegatingReverseEngineeringStrategy {

 public ExampleStrategy(ReverseEngineeringStrategy delegate) {
  super(delegate);
 }

 public String columnToPropertyName(TableIdentifier table, String column) {
  if(column.endsWith("PK")) {
   return "id";
  } else {
   return super.columnToPropertyName(table, column);
  }
 }
}

By default the reverse engineering is performed using the JDBC database metadata API. This is done via the class org.hibernate.cfg.reveng.dialect.JDBCMetaDataDialect, which is an implementation of org.hibernate.cfg.reveng.dialect.MetaDataDialect.

The default implementation can be replaced with an alternative implementation by setting the hibernatetool.metadatadialect property to a fully qualified class name for a class that implements JDBCMetaDataDialect.

This can be used to provide database specific optimized metadata reading. If you create an optimized metadata reader for your database it will be a very welcome contribution.