3.2.0.beta8
Table of Contents
Parameter |
Description |
Auto detected value |
---|---|---|
Name |
The unique name of the configuration |
Name of the selected project |
Property file |
Path to a hibernate.properties file |
First hibernate.properties file found in the selected project |
Configuration file |
Path to a hibernate.cfg.xml file |
First hibernate.cfg.xml file found in the selected project |
Entity resolver |
Fully qualified classname of a custom EntityResolver. Only required if you have special xml entity includes in your mapping files. |
No default value |
Enable Hibernate ejb3/annotations |
Selecting this option enables usage of annotated classes. hbm.xml files are of course still possible to use too. This feature requires running the Eclipse IDE with a JDK 5 runtime, otherwise you will get classloading and/or version errors. |
Not enabled |
Mapping files |
List of additional mapping files that should be loaded. Note: A hibernate.cfg.xml can also contain mappings. Thus if these a duplicated here, you will get "Duplicate mapping" errors when using the console configuration. |
If no hibernate.cfg.xml file is found, all hbm.xml files found in the selected project |
Classpath |
The classpath for loading POJO and JDBC drivers. Do not add Hibernate core libraries or dependencies, they are already included. If you get ClassNotFound errors then check this list for possible missing or redundant directories/jars. |
The default build output directory and any JARs with a class implementing java.sql.Driver in the selected project |
Clicking "Finish" creates the configuration and shows it in the "Hibernate Configurations" view
A very simple "click-and-generate" reverse engineering and code generation facility is also available. This facility allows you to generate a range of artifacts based on database or an already existing Hibernate configuration, be that mapping files or annotations. Some of these are POJO Java source file, Hibernate *.hbm.xml, hibernate.cfg.xml generation and even the option for generating the skeleton for a full Seam CRUD application.
To start working with this process, start the "Hibernate Code Generation" which is available in the toolbar via the Hibernate icon or via the "Run/Hibernate Code Generation" menu item.
When you click on "Hibernate Code Generation" the standard Eclipse launcher dialog will appear. In this dialog you can create, edit and delete named Hibernate code generation "launchers".
The dialog has the standard tabs "Refresh" and "Common" that can be used to configure which directories should be automatically refreshed and various general settings launchers, such as saving them in a project for sharing the launcher within a team.
The first time you create a code generation launcher you should give it a meaningfull name, otherwise the default prefix "New_Generation" will be used.
Note: The "At least one exporter option must be selected" is just a warning stating that for this launch to work you need to select an exporter on the Exporter tab. When an exporter has been selected the warning will disappear.
On the "Main" tab you the following fields:
Table 3.2. Code generation "Main" tab fields
Field |
Description |
---|---|
Console Configuration |
The name of the console configuration which should be used when code generating. |
Output directory |
Path to a directory into where all output will be written by default. Be aware that existing files will be overwritten, so be sure to specify the correct directory. |
Reverse engineer from JDBC Connection |
If enabled the tools will reverse engineer the database available via the connection information in the selected Hibernate Console Configuration and generate code based on the database schema. If not enabled the code generation will just be based on the mappings already specified in the Hibernate Console configuration. |
Package |
The package name here is used as the default package name for any entities found when reverse engineering. |
reveng.xml |
Path to a reveng.xml file. A reveng.xml file allows you to control certain aspects of the reverse engineering. e.g. how jdbc types are mapped to hibernate types and especially important which tables are included/excluded from the process. Clicking "setup" allows you to select an existing reveng.xml file or create a new one. See more details about the reveng.xml file in Chapter 5, Controlling reverse engineering. |
reveng. strategy |
If reveng.xml does not provide enough customization you can provide your own implementation of an ReverseEngineeringStrategy. The class need to be in the claspath of the Console Configuration, otherwise you will get class not found exceptions. See Section 5.3, “Custom strategy” for details and an example of a custom strategy. |
Generate basic typed composite ids |
A table that has a multi-colum primary key a |
Use custom templates |
If enabled, the Template directory will be searched first when looking up the templates, allowing you to redefine how the individual templates process the hibernate mapping model. |
Template directory |
A path to a directory with custom templates. |
The exporters tab is used to specify which type of code that should be generated. Each selection represents an "Exporter" that are responsible for generating the code, hence the name.
The following table describes in short the various exporters.
Table 3.3. Code generation "Exporter" tab fields
Field |
Description |
---|---|
Domain code |
Generates POJO's for all the persistent classes and components found in the given Hibernate configuration. |
JDK 1.5 constructs |
When enabled the POJO's will use JDK 1.5 constructs. |
EJB3/JSR-220 annotations |
When enabled the POJO's will be annotated according to the EJB3/JSR-220 persistency specification. |
DAO code |
Generates a set of DAO's for each entity found. |
Hibernate XML Mappings |
Generate mapping (hbm.xml) files for each entity |
Hibernate XML Configuration |
Generate a hibernate.cfg.xml file. Used to keep the hibernate.cfg.xml uptodate with any new found mapping files. |
Schema Documentation (.html) |
Generates set of html pages that documents the database schema and some of the mappings. |
Generate JBoss Seam skeleton app [Beta] |
Generates a complete JBoss Seam skeleton app. The generation will include annotated POJO's, Seam controller beans and a JSP for the presentation layer. See the generated readme.txt for how to use it. Note: this exporter generates a full application, including a build.xml thus you will get the best results if you use an output directory which is the root of your project. |
The Hibernate Mapping file editor provides XML editing functionality for the hbm.xml and cfg.xml files. The editor is based on the Eclipse WTP tools and extend its functionallity to provide hibernate specific code completion.
Package, class, and field completion is enabled for relevant XML attributes. The auto-completion detects it's context and limits the completion for e.g.
This is done via the standard hyperlink navigation functionallity in Eclipse; per default it is done by pressing F3 while the cursor is on a class/field or by pressing Ctrl and the mouse button to perform the same navigation.
For java completion and navigation to work the file needs to reside inside an Eclipse Java project, otherwise no completion will occur. Note: java completion does not require a hibernate console configuration to be used.
Table and column completion is also available for all table and column attributes.
Note that it requires a proper configured hibernate console configuration and this configuration should be the default for the project where the hbm.xml resides.
You can check which console configuration is selected under the Properties of a project and look under the "Hibernate Settings" page. When a proper configuration is selected it will be used to fetch the table/column names in the background.
Note: Currently it is not recommended to use this feature on large databases since it does not fetch the information iteratively. It will be improved in future versions.
In cfg.xml code completion for the value of
A reveng.xml file is used to customize and control how reverse engineering is performed by the tools. The plugins provide and editor to ease the editing of this file and hence used to configure the reverse engineering process.
The editor is intended to allow easy definition of type mappings, table include/excludes and specific override settings for columns, e.g. define a explicit name for a column when the default naming rules is not applicable.
Note that not all the features of the .reveng.xml file is exposed or fully implemented in the editor, but the main functionallity is there. To understand the full flexibility of the reveng.xml, please see Section 5.2, “hibernate.reveng.xml file”
The editor is activated as soon as an .reveng.xml file is opened. To get an initial reveng.xml file the reveng.xml wizard can be started via Ctrl+N or via the code generation launcher.
The following screentshot shows the overview page where the wanted console configuration is selected (auto-detected if Hibernate 3 support is enabled for the project)
The table filter page allows you to specify which tables to include and exclude. Pressing refresh shows the tables from the database that have not yet been excluded.
Type mappings page is used for specifying type mappings from jdbc types to any hibernate type (including usertypes) if the default rules are not applicable.
Table Columns page allow the user to explicit set e.g. which hibernatetype and propertyname that should be used in the reverse engineered model.
The Hibernate Console perspective combines a set of views which allow you to see the structure of your mapped entities/classes, edit HQL queries, execute the queries, and see the results. To use this perspective you need to create a console configuration.
To view your new configuration and entity/class structure, expand the Hibernate Console configuration by clicking on the + icon.
Clicking on the small + symbol allows you to browse the class/entity structure and see the relationships.
Hibernate Console perspective showing entity structure, query editor and result
A class diagram is available in the view named "Hibernate Entity Model". It will show the model when the Configuration node in a Hibernate Console Configuration is selected.
This view supports zoom in/out and can also be printed. Zooming is done via the toolbar buttons in the view and printing is done by selecting the view and choose File/Print or use the Print Icon.
Queries can be prototyped by entering them in the HQL editor. The HQL Editor is opened by right-clicking the Console configuration and select "HQL Scratchpad".
If the menu item is disabled then you need to first create an SessionFactory. That is done by right clicking the configuration and select "Create Session Factory" or by simpy expanding the Session Factory node.
Executing the query is done by clicking the green run button in the toolbar or pressing Ctrl+Enter.
Errors during creation of the SessionFactory or running the queries (e.g. if your configuration or query is incorrect) will be shown in a message dialog or inlined in the view that detected the error, you may get more information about the error in the Error Log view on the right pane.
Results of a query will be shown in the Query result view and details of possible errors (syntax errors, database errors, etc.) can be seen in the Error Log view.
Tip: HQL queries are executed using list() and without any limit of the size of the output. Be careful if you execute a query on a large result set. You might run out of memory. This will be improved in a future version.
If the "Hibernate Dynamic Query Translator" view is visible while writing in the HQL editor it will show the generated SQL for a HQL query.
The translation is done each time you stop typing into the editor, if there are an error in the HQL the parse exception will be shown embedded in the view.
The properties view shows the structure of any selected persistent object in the results view. Editing is not yet supported.
It is possible to configure the eclipse plugin to route all logging made by the plugins and hibernate code it self to the "Error log" view in Eclipse.
This is done by editing the "hibernate-log4j.properties" in org.hibernate.eclipse/ directory/jar. This file includes a default configuration that only logs WARN and above to a set of custom appenders (PluginFileAppender and PluginLogAppender). You can change these settings to be as verbose or silent as you please - see hibernate documentation for interesting categories and log4j documentation for how to configure logging via a log4j property file.
The hibernate-tools.jar contains the core for the Hibernate Tools. It is used as the basis for both the Ant tasks described in this document and the eclipse plugins both available from tools.hibernate.org The hibernate-tools.jar is located in your eclipse plugins directory at
/plugins/org.hibernate.eclipse.x.x.x/lib/tools/hibernate-tools.jar
. This jar is 100% independent from the eclipse platform and can thus be used independently of eclipse.
Note: until Hibernate 3.2 and related libraries are finally released there might be incompabilities with respect to the tools. Thus to avoid any confusion it is recommended to use the hibernate3.jar & hibernate-annotations.jar bundled with the tools when you want to use the Ant tasks. Do not worry about using e.g. Hibernate 3.2 jar's with e.g. an Hibernate 3.1 project since the output generated will work with previous Hibernate 3 versions.
To use the ant tasks you need to have the hibernatetool task defined. That is done in your build.xml by inserting the following xml (assuming the jars are in the lib directory):
this
Notice that to use the annotation based Configuration you must get a release from http://annotations.hibernate.org.
When using the
(1) templatepath="defaultTemplatePath" (2) > (3) (4) ( | | (5) | ) ( , , ,...*) (6)
(1) | destdir (required): destination directory for files generated with exporters. |
(2) | templatepath (optional): A path to be used to look up user-edited templates. |
(3) | classpath (optional): A classpath to be used to resolve resources, such as mappings and usertypes. Optional, but very often required. |
(4) | property and propertyset (optional): Used to set properties to control the exporters. Mostly relevant for providing custom properties to user defined templates. |
(5) | One of 4 different ways of configuring the Hibernate Meta Model must be specified. |
(6) | One or more of the exporters must be specified |
The following example shows the most basic setup for generating pojo's via hbm2java from a normal hibernate.cfg.xml. The output will be put in the ${build.dir}/generated directory.
The following example is similar, but now we are performing multiple exports from the same configuration. We are exporting the schema via hbm2dll, generates some DAO code via
hibernatetool supports four different Hibernate configurations: A standard Hibernate configuration (
Each have in common that they are able to build up a Hibernate Configuration object from which a set of exporters can be run to generate various output. Note: output can be anything, e.g. specific files, statments execution against a database, error reporting or anything else that can be done in java code.
The following section decribes what the the various configuration can do, plus list the individual settings they have.
A
(1) propertyfile="hibernate.properties" (2) entityresolver="EntityResolver classname" (3) namingstrategy="NamingStrategy classname" (4) > (5)
(1) | configurationfile (optional): The name of a Hibernate configuration file, e.g. "hibernate.cfg.xml" |
(2) | propertyfile (optional): The name of a property file, e.g. "hibernate.properties" |
(3) | entity-resolver (optional): name of a class that implements org.xml.sax.EntityResolver. Used if the mapping files require custom entity resolver. |
(4) | namingstrategy (optional): name of a class that implements org.hibernate.cfg.NamingStrategy. Used for setting up the naming strategy in Hibernate which controls the automatic naming of tables and columns. |
(5) | A standard Ant fileset. Used to include hibernate mapping files.Remember that if mappings are already specified in the hibernate.cfg.xml then it should not be included via the fileset as it will result in duplicate import exceptions. |
This example shows an example where no hibernate.cfg.xml exists, and a hibernate.properties + fileset is used instead. Note, that Hibernate will still read any global /hibernate.properties available in the classpath, but the specified properties file here will override those values for any non-global property.
An
The
Thus the minimal usage is:
An
The persistenceunit attribute can be used to select a specific persistence unit. If no persistenceunit is specified it will automatically search for one and if a unique one is found use it, but if multiple persistence units are available it will error.
To use an
Note: ejb3configuration were the name used in previous versions. It still works but will emit a warning telling you to use jpaconfiguration instead.
A
This configuration works by reading the connection properties from
The
(1) revengfile="hibernate.reveng.xml" (2) reversestrategy="ReverseEngineeringStrategy classname"(3) detectmanytomany="true|false" (4) detectoptmisticlock="true|false" (5) > ...
(1) | packagename (optional): The default package name to use when mappings for classes is created |
(2) | revengfile (optional): name of reveng.xml that allows you to control various aspects of the reverse engineering. |
(3) | reversestrategy (optional): name of a class that implements org.hibernate.cfg.reveng.ReverseEngineeringStrategy. Used for setting up the strategy the tools will use to control the reverse engineering, e.g. naming of properties, which tables to include/exclude etc. Using a class instead of (or as addition to) a reveng.xml file gives you full programmatic control of the reverse engineering. |
(4) | detectManytoMany (default:true): If true (the default) tables which are pure many-to-many link tables will be mapped as such. A pure many-to-many table is one which primary-key contains has exactly two foreign-keys pointing to other entity tables and has no other columns. |
(5) | detectOptimisticLock (efault:true): If true columns named VERSION or TIMESTAMP with appropriate types will be mapped with the apropriate optimistic locking corresponding to |
Here is an example of using
Exporters is the parts that does the actual job of converting the hibernate metamodel into various artifacts, mainly code. The following section describes the current supported set of exporters in the Hibernate Tool distribution. It is also possible for userdefined exporters, that is done through the
(1) update="true|false" (2) drop="true|false" (3) create="true|false" (4) outputfilename="filename.ddl" (5) delimiter=";" (6) format="true|false" (7) >
(1) | export (default: true): Execute the generated statements against the database |
(2) | update(default: false): Try and create an update script representing the "delta" between what is in the database and what the mappings specify. Ignores create/update attributes. (Do *not* use against production databases, no guarantees at all that the proper delta can be generated nor that the underlying database can actually execute the needed operations) |
(3) | drop (default: false): Output will contain drop statements for the tables, indices & constraints |
(4) | create (default: true): Output will contain create statements for the tables, indices & constraints |
(5) | outputfilename (Optional): If specified the statements will be dumped to this file. |
(6) | delimiter (default: ";"): What delimter to use to separate statements |
(7) | format (default: false): Apply basic formatting to the statements. |
Basic example of using
(1) ejb3="true|false" (2) >
(1) | jdk (default: false): Code will contain JDK 5 constructs such as generics and static imports |
(2) | ejb3 (default: false): Code will contain EJB 3 features, e.g. using annotations from javax.persistence and org.hibernate.annotations |
Basic example of using
Basic usage of
(1) />
(1) | ejb3 (default: false): the generated cfg.xml will have |
[a HQL query string]
Currently one session is opened and used for all queries and the query is executed via the list() method. In the future more options might become available, like performing executeUpdate(), use named queries etc.
Simplest usage of
from java.lang.Object
Multiple queries can be executed by nested
select c.name from Customer c where c.age > 42 from Cat
Generic exporter that can be controlled by a user provided template or class.
NOTICE: Previous versions of the tools used Velocity. We are now using Freemarker which provides us much better exception and error handling.
The following is an example of reverse engineering via
Exporters can be controlled by user properties. The user properties is specificed via
The
Most times using
If the templates need to access some user class it is possible by specifying a "toolclass" in the properties.
Placing the above
Here is an example that uses
When using the
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 foreignkeys into classes, properties and associations. It also used to provide mappings from SQL types to Hibernate types. The strategy can be customized by the user. The user can even provide its own custom reverse engineering strategy if the provided strategy is not enough, or simply just provide a small part of the strategy and delegate the rest to the default strategy.
The default strategy uses some rules for mapping JDBC artifact names to java artifact names. It also provide basic typemappings from JDBC types to Hibernate types. It is the default strategy that uses the packagename attribute to convert a table name to a fully qualified classname.
To have fine control over the process a hibernate.reveng.xml file can be provided. In this file you can specify type mappings and table filtering. This file can be created by hand (its just basic XML) or you can use the Hibernate plugins which have a specialized editor.
Note: many databases is case-sensitive with their names and thus if you cannot make some table match and you are sure it is not excluded by a
The following is an example of a reveng.xml. Following the example is more details about the format.
seq_table
By default the reverse engineering will read all schemas and then use
With
Note: If no
which in turn is equal to:
The following will process all tables from MY_SCHEMA.
It is possible to have multiple schema-selection's to support multi-schema reading or simply to limit the processing to very specific tables. The following example process all tables in MY_SCHEMA, a specific CITY table plus all tables that starts with CODES_ in COMMON_SCHEMA.
The
The number of attributes specificed and the sequence of the sql-type's is important. Meaning that 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 the importance of ordering of the type mappings.
The following table shows how this affects an example table named CUSTOMER:
Table 5.1. sql-type examples
Column | jdbc-type | length | precision | not-null | Resulting hibernate-type | Rationale |
---|---|---|---|---|---|---|
ID | INTEGER | 10 | true | int | Nothing defined for INTEGER. Falling back to default behavior. | |
NAME | VARCHAR | 30 | false | your.package.TrimStringUserType | No type-mapping matches length=30 and not-null=false, but type-mapping matches the 2 mappings which only specifies VARCHAR. The type-mapping that comes first is chosen. | |
INITIAL | VARCHAR | 1 | false | char | Even though there is a generic match for VARCHAR, the more specifc type-mapping for VARCHAR with not-null="false" is chosen. The first VARCHAR sql-type matches in length but has no value for not-null and thus is not considered. | |
CODE | VARCHAR | 1 | true | java.lang.Character | The most specific VARCHAR with not-null="true" is selected. | |
SALARY | NUMERIC | 15 | false | big_decimal | There is a precise match for NUMERIC with precision 15 | |
AGE | NUMERIC | 3 | false | java.lang.Long | type-mapping for NUMERIC with not-null="false" |
The
(1) match-schema="schema_matching_rule" (2) match-name="table_matching_rule" (3) exclude="true|false" (4) package="package.name" (5) />
(1) | match-catalog (default: .*): Pattern for matching catalog part of the table |
(2) | match-schema (default: .*): Pattern for matching schema part of the table |
(3) | match-table (default: .*): Pattern for matching table part of the table |
(4) | exclude (default: false): if true the table will not be part of the reverse engineering |
(5) | package (default: ""): The default package name to use for classes based on tables matched by this table-filter |
(1) | catalog (Optional): Catalog name for table. Has to be specified if you are reverse engineering multiple catalogs or if it is not equal to hiberante.default_catalog |
(2) | schema (Optional): Schema name for table. Has to be specified if you are reverse engineering multiple schemas or if it is not equal to hiberante.default_schema |
(3) | name (Required): Name for table |
(4) | clase (Optional): The class name for table. Default name is camelcase version of the table name. |
A
(1) parameter value (2) (3)
(1) | generator/class (Optional): defines which identifier generator should be used. The class name is any hibernate short hand name or fully quailfied class name for an identifier strategy. |
(2) | generator/param (Optional): Allows to specify which parameter with name and value should be passed to the identifier generator |
(3) | key-column (Optional): Specifies which column(s ) the primary-key consists of. A key-column is same as column, but does not have the exclude property. |
With a
(1) jdbc-type="java.sql.Types type" (2) type="hibernate_type" (3) property="propertyName" (4) exclude="true|false" (5) />
(1) | name (Required): Column name |
(2) | jdbc-type (Optional): Which jdbc-type this column should be processed as. A value from java.sql.Types, either numerical (93) or the constant name (TIMESTAMP). |
(3) | type (Optional): Which hibernate-type to use for this specific column. |
(4) | property (Optional): What property name will be generated for this column. |
(5) | exclude (default: false): set to true if this column should be ignored. |
The
Note
(1) foreign-catalog="catalogName" (2) foreign-schema="schemaName" (3) foreign-table="tableName" (4) > (5)"foreignColumnName"/> (6) property="aPropertyName" exclude="true|false"/> (7)
(1) | constraint-name (Required): Name of the foreign key constraint. Important when naming many-to-one and set. It is the constraint-name that is used to link the processed foreign-keys with the resulting property names. |
(2) | foreign-catalog (Optional): Name of the foreign table's catalog. (Only relevant if you want to explicitly define a foreign key) |
(3) | foreign-schema (Optional): Name of the foreign table's schema. (Only relevant if you want to explicitly define a foreign key) |
(4) | foreign-table (Optional): Name of the foreign table. (Only relevant if you want to explicitly define a foreign key) |
(5) | column-ref (Optional): Defines that the foreign-key constraint between a local-column and foreign-column name. (Only relevant if you want to explicitly define a foreign key) |
(6) | many-to-one (Optional): 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. |
(7) | set (Optional): 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. |
It is possible to implement a user strategy. Such strategy must implement org.hibernate.cfg.reveng.ReverseEngineeringStrategy. It is recommended that one uses the DelegatingReverseEngineeringStrategy and provide a public constructor which takes another ReverseEngineeringStrategy as argument. This will allow you to only implement the relevant methods and provide a fallback strategy. Example of custom delegating strategy which converts all column names that ends 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 by reading 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 property hibernatetool.metadatadialect to a fully qualified classname for a class that implements JDBCMetaDataDialect.
This can be used to provide database specific optimized metadata reading. If you create an optimized/better metadata reading for your database it will be a very welcome contribution.
When using
The 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 tag to e.g. 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 shows how to use various attributes and the resulting java code.
Javadoc for the Person class @author Frodo IAuditable protected The name of the person
The above hbm.xml 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 { public Long id; public String name; public Person(java.lang.String name) { this.name = name; } 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 6.1. Supported meta tags
Attribute | Description |
---|---|
class-description | inserted into the javadoc for classes |
field-description | inserted into the javadoc for fields/properties |
interface | If true an interface is generated instead of an class. |
implements | interface the class should implement |
extends | class the class should extend (ignored for subclasses) |
generated-class | overrule the name of the actual class generated |
scope-class | scope for class |
scope-set | scope for setter method |
scope-get | scope for getter method |
scope-field | scope for actual field |
default-value | default initializatioin value for a field |
use-in-tostring | include this property in the toString() |
use-in-equals | include this property in the equals() and hashCode() method. If no use-in-equals is specificed, no equals/hashcode will be generated. |
gen-property | property will not be generated if false (use with care) |
property-type | Overrides the default type of property. Use this with any tag's to specify the concrete type instead of just Object. |
class-code | Extra code that will inserted at the end of the class |
extra-import | Extra import that will inserted at the end of all other imports |
Attributes declared via the 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 IAuditable in the top of the hbm.xml file, just after
Note: This applies to all -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 protected at e.g. just under the
To avoid having a -tag inherited then you can simply specify inherit="false" for the attribute, e.g. public abstract will restrict the "class-scope" to the current class, not the subclasses.
We expound here some good practices when using attributes.
Le'ts we have two entities: Person and Event and there is bi-directional association between them, so we provide the methods: Event.getPersons() and Person.getEvents(). If we define at class scope level of the Persona.hbm, Event.hbm the meta attributes: use-in-string, use-in-equals:
true true ...
and for Event.hbm file:
true true
The generated code will produce infinite loop on the generated methods: toString()/equals(), for example:
// default package // Person Class: import java.io.Serializable; public class Person implements Serializable { // .... (Omitted) public Set getEvents() { return this.events; } public void setEvents(Set events) { this.events = events; } /** * toString * @return String */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(getClass().getName()).append("@").append(Integer.toHexString(hashCode())).append(" ["); //... buffer.append("events").append("='").append(getEvents()).append("' "); buffer.append("]"); return buffer.toString(); } // ...}
and for Event.java:
// default package // Event Class: import java.io.Serializable; public class Person implements Serializable { // .... (Omitted) public Set getPersons() { return this.persons; } public void setParticipants(Set persons) { this.participants = participants; } /** * toString * @return String */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(getClass().getName()).append("@").append(Integer.toHexString(hashCode())).append(" ["); //... buffer.append("participants").append("='").append(getParticipants()).append("' "); buffer.append("]"); return buffer.toString(); } // ...}
So when invoking Person.toString() you get an infinite loop, because it internally invokes the method: Person.getEvents() and the Set.toString() method will invoke for each element of the set the toString() method, so the method Event.toString() internally invokes Event.getParticipants(), that again uses Person.toString() for each element of Event.getParticipantss() method.
The same occurs for the equals() method. You have to decide which side of the association will include the other part on the toString()/equals() definition. Therefore it is not a good practice to put at class scope such meta attributes, unless you are defining a leap class (with no inverse association)
We recomend instead of putting the attributes use-in-tostring and use-in-equals at class scope level just select the properties you want to include on methods toString()/equals() at property scope level:
true true true true
and now for Person:
Javadoc for the Person class @author Frodo IAuditable protected true The name of the person true
For equal()/hashCode() method generation, you also have to take into account that the attributes that participate on such method definition, should take into account only attributes with business meaning (the name, social security number, etc, but no generated id's, for example).
Hibernate needs a way to distinguish that two instances created independently if they are transient object or not, mainly for collections. Otherwise there is no way to add new elements to a set if Hibernate considers via equals()/hashCode() are the same. If we define equals() method that delegate only on information that will be generated when the object become persistent, there is no way to distinguish transient element.
Therefore automatically configuration the generation of equals()/hashCode() methods specifying at class scope level the attribute use-in-equals could be a dangerous decision that could produce non expected side-effect.
On this section we consider some advanced example for configurating the code generation via attributes, for example defining new custom attributes
Using source-code attribute, you can add addional methods on a given class, nevertheless such attribute can not be used at property scope level and Hibernatetools does not provide such attributes.
A solution for that is "create" a new template, for example modifying the freemarker template responsable for generating the POJO's. If you look inside hibernate-tools.jar, you can find the template: pojo/PojoPropertyAccessor.ftl
Extract the PojoPropertyAccessor.ftl into a local folder i.e. ${hbm.template.path}, respecting the hole path, for example: ${hbm.template.path}/pojo/PojoPropertyAccessor.ftl
If you look in to the file you can detect easy where is generated the set method.
${pojo.getPropertySetModifiers(property)} void set${pojo.getPropertyName(property)}(${pojo.getJavaTypeName(property, jdk5)} ${property.name}) { this.${property.name} = ${property.name}; }
We can add conditionally pre/post-conditions on our set method generation just adding a little Freemarker syntax to the above source code:
${pojo.getPropertySetModifiers(property)} void set${pojo.getPropertyName(property)}(${pojo.getJavaTypeName(property, jdk5)} ${property.name}) { <#if pojo.hasMetaAttribute(property, "pre-cond")> ${c2j.getMetaAsString(property, "pre-cond","/n")} #if> this.${property.name} = ${property.name}; <#if pojo.hasMetaAttribute(property, "post-cond")> ${c2j.getMetaAsString(property, "post-cond","/n")} #if> }
Now if in any *hbm.xml file we define the attributes: pre-cond or post-cond, its values will be introduced on the body of the generated set method.
Let's say we want to add pre-condition for property name preventing no Person can have an empty name. So we have to modify the Person.hbm.xml file like this:
Notes: i) If you don't use <[[CDATA[]]> you have to scape the & symbol, i.e.: & ii) We can use an assert condition, but remember it is not a good practice for public methods.
Finally we have to generate the Person.java class, so we have to configure
Invoking the target
// default package import java.io.Serializable; public class Person implements Serializable { public Long id; public String name; public Person(java.lang.String name) { this.name = name; } public Person() { } public java.lang.Long getId() { return this.id; } public void setId(java.lang.Long id) { this.id = id; } public java.lang.String getName() { return this.name; } public void setName(java.lang.String name) { if ((name != null) && (name.length() == 0)) { throw new IllegalArgumentException("name can not be an empty String"); } this.name = name; } }
In a similar way a post-condition could be added.