
Hibernate / Middlegen - Inheritance and Many To Many v1.0
Part 2 in the Warfrog.com tutorial series
written by Tyler Pitchford
http://www.warfrog.com
Before we begin
What this tutorial covers
This tutorial covers how to modify the hbm.xml files generated by Middlegen to correctly produce Inheritance and Many to Many relationships when processed by HBM2JAVA. Furthermore, this tutorial assumes you have a working knowledge of these technologies and their related terminology.
What this tutorial
doesn't cover
This tutorial does not cover the basics of Hibernate, Middlegen, etc.
If you're new to the world of Hibernate and Middlegen I'd suggest you read the
first part of this tutorial series located
here.
Downloading / Installing optional software
Install ANT
Get newest version
URL: http://ant.apache.org/manual/index.html
Install: Follow instructions at the URL above
Setting up the project
Create the staging folder
Note: I picked C:\hibernatetutorial2, you can use whatever you like, but I'll be
assuming C:\hibernatetutorial2 for the rest of this document.
Extract the hibernatetutorial2.zip to C:\hibernatetutorial2. After that you'll need to open a command prompt to c:\hibernatetutorial2 and type "ant setup-dirs"
OR if you've decided not to use ANT
Time to install some software Note: Every "extract the zip file..." line below means extract the zip file directly to the folder. Do not change the root dir and/or
"extract to FILENAME directory." There may be some repetitive folder
names, just ignore them (ex. C:\hibernatetutorial\apps\hsqldb\hsqldb ). If you
change the root directory you'll need to manually edit the build.xml, I've
provided, to point to the correct application roots. Additionally, if any
of the versions of the software listed below change you'll need to update the
build.xml.
Open a
command prompt to c:\hibernatetutorial2 and type "ant setup-middlegen" OR if you've decided not to use ANT
Create the following directories:
Install HSQLDB
Download: hsqldb_1_7_X.zip
File used in this tutorial: hsqldb_1_7_1.zip
URL:
http://sourceforge.net/project/showfiles.php?group_id=23316&release_id=117043
Install: Extract the zip file to the hsqldb directory within the apps directory
Install Hibernate
Download: hibernate-2.1.X.zip
File used in this tutorial: hibernate-2.1.3.zip
URL:
http://prdownloads.sourceforge.net/hibernate/?sort_by=date&sort=desc
Install: Extract to the hibernate directory inside the apps directory
Install Hibernate extensions
Download: hibernate-extensions-2.1.X.zip
File used in this tutorial: hibernate-extensions-2.1.2.zip
URL:
http://prdownloads.sourceforge.net/hibernate/?sort_by=date&sort=desc
Install: Extract to the hibernate-ext directory inside the apps directory
Install Middlegen
Download: Middlegen-Hibernate-rX.zip
File used in this tutorial: Middlegen-Hibernate-r4.zip
URL:
http://prdownloads.sourceforge.net/hibernate/?sort_by=date&sort=desc
Install: Extract to the middlegen directory inside the apps directory
Copy the following files:
to the C:\hibernatetutorial2\apps\middlegen\lib directory
Copy the following files:
to the C:\hibernatetutorial2\apps\middlegen\middlegen-lib directory.
Delete the following directories / files:
C:\hibernatetutorial2\apps\middlegen\middlegen-lib\middlegen-2.0-vo.jar
C:\hibernatetutorial2\apps\middlegen\middlegen-lib\middlegen-hibernate-plugin-2.0-vo.jar
Copy the build.xml, provided in the hibernatetutorial2.zip, to C:\hibernatetutorial2\apps\middlegen\.
Additionally, copy the hsqldb.xml to the C:\hibernatetutorial2\apps\middlegen\config\database\hsqldb.xml.
Setup the HSQLDB database
Launch the HSQLDB GUI

Launch a command prompt to C:\hibernatetutorial2\apps\hsqldb\hsqldb\lib directory.
Launch the HSQLDB GUI by typing "java -cp hsqldb.jar
org.hsqldb.util.DatabaseManager"
Set the type to: HSQL Database Engine Standalone
Set the URL to: jdbc:hsqldb:../../../../hsqldb/hibernatetutorial2
Leave the rest of the settings alone
Click Ok
Two files were just created that make up the hibernatetutorial2 database
Create the PERSONS Table
Paste the following code into the text box next to the execute button
CREATE TABLE PERSONS (
person_id int NOT NULL IDENTITY,
first_name LONGVARCHAR(255) NOT NULL,
last_name LONGVARCHAR(255) NOT NULL,
dob DATE NOT NULL,
ssn LONGVARCHAR(20) NOT NULL,
address_1 LONGVARCHAR(255) NOT NULL,
address_2 LONGVARCHAR(255),
phone LONGVARCHAR(50) NOT NULL,
active bit DEFAULT 'true' NOT NULL
)
Hit execute
Create the EMPLOYEES Table
Paste the following code into the text box next to the execute button
CREATE TABLE EMPLOYEES (
employee_id int NOT NULL PRIMARY KEY,
salary decimal(20,4) NOT NULL,
foreign key (employee_id) references persons (person_id)
)
Create the DEPARTMENTS Table
Paste the following code into the text box next to the execute button
CREATE TABLE DEPARTMENTS (
department_id int NOT NULL IDENTITY,
name LONGVARCHAR(50) NOT NULL,
description LONGVARCHAR(255)
)
Create the EMPLOYEES_DEPARTMENTS Table
Paste the following code into the text box next to the execute button
CREATE TABLE EMPLOYEES_DEPARTMENTS(
employee_id int NOT NULL,
department_id int NOT NULL,
foreign key (employee_id) references employees (employee_id),
foreign key (department_id) references departments (department_id),
primary key(employee_id, department_id)
)
Hit execute
Close the GUI but leave the console open, we'll be using it in a minute.
Launch the HSQLDB Server
You've just created the groups and users tables we'll be using in our tutorial.
Now all we have to do is launch the HSQLDB Server so we can access the database
easily from our application. Open another command prompt to the C:\hibernatetutorial2\hsqldb directory.
Make sure you don't use the command prompt we launched the HSQLDB GUI from,
create another command prompt, because we'll be using it in a minute to test our
database. Launch the HSQLDB server by typing "java -cp ../apps/hsqldb/hsqldb/lib/hsqldb.jar
org.hsqldb.Server -database hibernatetutorial2" at the command prompt. If
all went as planned you should see something similar to "Sat May 15 12:01:41 EDT 2004 Listening
for connections ..." at the bottom of the command prompt. However, if you
see "java.sql.SQLException: The database is already in use by another process",
make sure you've closed the HSQLDB GUI.
Test the HIBERNATETUTORIAL2 Database
Relaunch the HSQLDB GUI.
Set the type to: HSQL Database Engine Server
Leave the rest of the settings alone
Click Ok
Assuming everything has gone smoothly you should see the PERSONS, EMPLOYEES,
DEPARTMENTS, and EMPLOYEES_DEPARTMENTS tables
in the left-hand tree. Congratulations, you're HSQLDB is now fully
operation and you're ready to move on to generating you first Hibernate Mapping
files. Once again, leave the HSQLDB GUI open.
Using Middlegen

Launching Middlegen
Open a command prompt to C:\hibernatetutorial2\apps\middlegen\Middlegen-Hibernate-r4
and type "ant middlegen." You should now see a screen containing your
PERSONS, EMPLOYEES, DEPARTMENTS, and EMPLOYEES_DEPARTMENTS tables. Click on the title bar of the
PERSONS table and change the Key Generator type to "Native." Repeat the same process for
DEPARTMENTS table. Leave the EMPLOYEES_DEPARTMENTS and EMPLOYEES tables alone.
Additionally, click on the PERSONS table and change the "Active" field to
Boolean, just to be consistent with the other fields (they're all Objects). Click the Generate button and wait for it to turn back to light grey. Close the Middlegen GUI.
to Inheritance
The middlegen plugin is still a work in progess. It greatly reduces the work
load required to generate the hbm.xml files that both hbm2java and hibernate require, but
it still requires a little manual labor. Middlegen attempts to automatically
adjust the table names to proper class names (ex. table: users to class: User).
Generally, middlegen does a great job at this, but in certain cases it makes a
mistake or two. In our example Middlegen has converted employees_departments to
EmployeesDepartment, because it removes the "s" it detected on the "departments"
portion of the table name. Unfortunately, it didn't remove the "s" from employees
for us. To fix this we'll need to make a few modifications to the
EmployeesDepartment.hbm.xml file. First, rename the file to
EmployeesDepartment.hbm.xml to EmployeeDepartment.hbm.xml. Next, open
EmployeeDepartment.hbm.xml and modify the lines:
<class
name="com.warfrog.hibernatetutorial2.hibernate.EmployeesDepartment"
Save the file and exit the editor. Hopefully, in the near future the Middlegen-Hibernate
plugin will allow users to edit the names used to generate the hbm.xml files,
but until then we'll just have to modify them after generation.
<class
name="com.warfrog.hibernatetutorial2.hibernate.EmployeeDepartment"
Now that we have all of our files correctly named, we need to make a few more
modifications to them. Middlegen currectly doesn't correctly generate the
many-to-many relationships we want nor does it generate the inheritance mappings
we're trying to achieve. Fortunately, the modifications we need to make are
simple and Middlegen has handled a large part of the grunt work for us. Let's
start with the inheritance modifications.
Setting up Inheritance
Since persons and employees have a one-to-one relationship, we want the generated java classes to have a relationship of Person (superclass) to Employee (subclass). To create the inheritance we're looking for we need to utilize hibernate's <joined-subclass> element. Open then Employee.hbm.xml and change:
<class... </class>
to
<joined-subclass
...
</joined-subclass>
Now, hightlight from <joined-subclass> to </joined-subclass> and copy it to your clipboard. Open the Person.hbm.xml and paste the <joined-subclass> information right before the </class> element at the bottom of the Person.hbm.xml.
<PASTE HERE>
</class>
</hibernate-mapping>
We'll also need to remove the <one-to-one> mapping to Person, that Middlegen added to the Employee element. If you don't delete the <one-to-one> mapping it'll cause Hibernate to throw an exception informing you that you haven't supplied a required element, the Person object. Next, find the <id> element of our newly pasted <joined-subclass> element and delete from <id> to </id>. Now paste the following code in it's place:
<key column="employee_id"/>
We've just told hibernate that we want Employee to be a subclass of Person and it should use employee_id as it's id column. We only need to make a few more modifications and we'll be all done with this section. Find the <one-to-one> association inside User.hbm.xml. Below outer-join="auto" add "cascade="delete". This informs hibernate that if we delete a Person object we also want to delete the Employee object associated to it (if there is one). Save the file and exit your editor. Finally, we need to delete the Employee.hbm.xml file, so we don't double generate the Employee class (once from the <joined-subclass> element inside Person.hbm.xml and once from Employee.hbm.xml). We're now done with our inheritance setup, so now lets move on to setting up proper many-to-many relationships.
Note: Once we've run hbm2java you may wish to remove the generated getBrokers() and setBrokers() accessor/mutator methods hbm2java generates. I personally don't like my Parent class having any knowledge of it's subclasses, but that's a personal choice.
Many to Many
Setting up Many to Many associations
Currently, the Employee and Department hbm.xml files Middlegen generated for us both have a one-to-many relationship to the EmployeeDepartment.hbm.xml file. As the relationships are defined now we would have to call code similar to this:
//retrieve the EmployeeDepartment objects
Set employeesDepartments = employee.getEmployeesDepartments();
//now we need to move through the set, retrieve the EmployeeDepartment object
//then each EmployeeDepartment for it's associated Department object.
//now we can work with the Department
While this is usable in an application, it's much cleaner to simply call employee.getDepartments(); and directly receive a Set of Department objects. So, lets get to it.
First, open Person.hbm.xml in your favorite editor and find the <set> element related to EmployeesDepartments (it's inside the Employee </joined-subclass>). Highlight from the comment above the <set> element all the way to the closing </set> element and delete it. Now copy the following code in it's place:
<!-- bi-directional many-to-many association to Department -->
<set name="departments" table="employees_departments" inverse="true" cascade="all">
<key column="employee_id"/>
<many-to-many column="department_id" class="com.warfrog.hibernatetutorial2.hibernate.Department"/>
</set>
Now open Department and repeat the procedure pasting this code instead:
<!-- bi-directional many-to-many association to Employee -->
<set name="employees" table="employees_departments" cascade="all">
<key column="department_id"/>
<many-to-many column="employee_id" class="com.warfrog.hibernatetutorial2.hibernate.Employee"/>
</set>
Note: If you look closely you'll notice that the Deparment code doesn't contain an inverse="true" element. Adding this element to both ends of the relationship results in some odd/undesirable behavior. For more information please consult this url ( http://www.hibernate.org/155.html ).HBM2JAVA
Generating our Java files
Open a command prompt to you middlegen directory and execute "ant hbm2java". Once the ANT task has completed you should have 4 java files in your gen-src/com/warfrog/hibernatetutorial2/hibernate directory. You should now have a total of 7 files:
Department.hbm.xml
EmployeeDepartment.hbm.xml
Person.hbm.xml
Department.java
Employee.java
EmployeeDepartment.java
Person.java
If you take the time to examine the the java files hbm2java has generated you'll noticed that Employee contains a getDepartments() method, Department contains a getEmployees() method, and the Employee extends Person. At this point you can utilize the afforementioned files to properly insert, update, delete Person, Department, and Employee objects. Below I've provided some sample code on how to insert a new Employee with a new Department associated to it.
try{
//notice we don't specify the Employee.class below
Configuration cfg = new Configuration()
.addClass(Department.class)
.addClass(Person.class)
.addClass(EmployeeDepartment.class);
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
//create an employee, take notice that we set both Person and Employee info
Employee employee = new Employee();
employee.setActive(new Boolean(true));
employee.setAddress1("TEST ADDRESS 1");
employee.setAddress2("TEST ADDRESS 2");
employee.setDob(new Date());
employee.setFirstName("TEST_FIRST_NAME");
employee.setLastName("TEST_LAST_NAME");
employee.setPhone("18005557500");
employee.setSalary(new BigDecimal(10000000));
employee.setSsn("000-00-0000");
//create a Department
Department department = new Department();
department.setName("TEST_DEPARTMENT");
//not the we've left out Description, which we can do since we marked it's not marked as "NOT NULL"
//link the department to the employee
employee.setDepartments(new HashSet());
employee.getDepartments().add(department);
//link the employee to the department
department.setEmployees(new HashSet());
department.getEmployees().add(employee);
//now we need to save the objects to the database
session.save(employee);
//you could have called this instead since we defined cascade="all"
//Session.save(department);
tx.commit();
}catch(Exception e){
e.printStackTrace();
}
executing the code above should result in output similar to this:
Hibernate: insert into PERSONS (FIRST_NAME, LAST_NAME, DOB, SSN, ADDRESS_1, ADDRESS_2, PHONE, ACTIVE, PERSON_ID) values (?, ?, ?, ?, ?, ?, ?, ?, null)
Hibernate: CALL IDENTITY()
Hibernate: insert into EMPLOYEES (SALARY, employee_id) values (?, ?)
Hibernate: insert into DEPARTMENTS (NAME, DESCRIPTION, DEPARTMENT_ID) values (?, ?, null)
Hibernate: CALL IDENTITY()
Hibernate: insert into employees_departments (department_id, employee_id) values (?, ?)
If you need further proof that everything worked, launch the HSQLDB GUI and execute the following statements:
Conclusion
Conclusion
I hope this tutorial has given you a better understanding of how to accomplish some fairly common tasks with some great tools. If you're new to Hibernate and Middlegen then I'd suggest you read my first tutorial and some of the resources listed below. Doing so, should give you a richer and deeper understanding of how to utilize Hibernate in real world projects. As always, if you have any questions or comments don't hesitate to contact me either through IRC or email.
Cheers,
Tyler Pitchford
Senior Developer - Warfrog.com
Resources
Other tutorials
Warfrog Hibernate tutorial series part 1 - Hibernate/Spring/Middlegen/Xdoclet: http://www.warfrog.com/hibernatetutorial
Introduction to Hibernate:
http://www.systemmobile.com/articles/IntroductionToHibernate.html
MiddleGen-Hibernate Example:
http://www.systemmobile.com/articles/IntroductionToHibernate.html
Object-relation mapping without the container:
http://www-106.ibm.com/developerworks/library/j-hibern/?ca=dnt-515
Object to Relational Mapping and Relationships with Hibernate:
www.meagle.com:8080/hibernate.jsp
Links
Ant: http://ant.apache.org/
Ant Documentation:
http://ant.apache.org/manual/index.html
Eclipse: http://www.eclipse.org/
Eclipse Documentation: http://www.eclipse.org/
Hibernate: http://www.hibernate.org
Hibernate Documentation:
http://www.hibernate.org/hib_docs/reference/en/html/
Spring:
http://www.springframework.org/
Spring Documentation:
http://www.springframework.org/documentation.html
Middlegen:
http://boss.bekk.no/boss/middlegen/
Middlegen Documenation:
http://boss.bekk.no/boss/middlegen/project-info.html
XDoclet:
http://xdoclet.sourceforge.net/
XDoclet Documenation:
http://xdoclet.sourceforge.net/project-info.html
Hibernate - Xdoclet:
http://www.hibernate.org/72.html
Hibernate - Spring:
http://hibernate.bluemars.net/110.html
Hibernate - Inverse information: http://www.hibernate.org/155.html
IRC Help
#hibernate on irc.freenode.org
#spring on irc.freenode.org
#java on irc.freenode.org
Contact Info
IRC Handle: TdC_VgA
tyler_pitchford <remove>at<remove> yahoo.com
Downloads
Tutorial Files: hibernatetutorial2.zip
Change Log
Revisions
v1.0 - Inital Release