Readily available tools like Hibernate (see Resources) have dramatically reduced the impedance created between Java objects and their database storage; specially, the ease with which Java classes can now be annotated to specify the way objects should be persisted. Developers are freed from the onerous task of writing up database integration codes. Hibernate solves the persistence issue; however, Web pages need to be created to handle these elements. A typical scenario for a medium-sized Web application can proceed something like this: The developer starts by coding the Plain Old Java Objects (POJOs) that represent a particular domain model, and then proceeds to create the different transactions and the Web user interface. A subset of the elements of the model will frequently involve non-transactional data. Customers, clients, countries, locations, employees, and companies are typical elements of a business model that are maintained by a few operators.
Why not generate the Web presentation layer to create, add, list, delete, and search these elements from the annotated beans? And why not make this presentation a friendly Ajax experience? These are the main goals of the jpa2web tool, which has the following process flow:
- Input: POJO-annotated beans (and optional templates).
- Output: An Ajax Web application to handle and persist the elements of the model.
- Technologies used: FreeMarker + ZK + Hibernate (see Resources for links to more information on these technologies).
The tool uses annotation-driven programming mainly to specify ORM mappings. Many of these annotations can be reused to define the Web interface or to create modifiable prototypes.
The following sections illustrate how beans of different complexities can be mapped to an Ajax Web user interface using jpa2web. Next, you'll get an outline of how the jpa2web algorithm works and some basic instructions to get it working. Finally, the article concludes with a description of the applicability of jpa2web and future enhancements to the tool.
A sample domain model is used throughout this article, which might be familiar to
some readers. It consists of an adaptation of the sample domain model used in the great book Enterprise JavaBeans, 3.0 by Bill Burke and Richard Monson-Haefel (see Resources for a link). This domain model contains a ship management class Ship.java (see Listing 1), which is the simplest kind of POJO: a class with primitive members.
Listing 1.
Ship.java
package com.titan.domain;
import javax.persistence.*;
@Entity
public class Ship implements java.io.Serializable
{
private int id;
private String name;
private double tonnage;
@Id @GeneratedValue
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getTonnage() { return tonnage; }
public void setTonnage(double tonnage) { this.tonnage = tonnage; }
public String toString() { return name; }
}
|
If you want to manipulate instances of Ship.java in sync with
a database, you need basically two kind of user interfaces: one to add (or edit)
ships, and another to list them. The first case will look like a form used to enter
the details of the ship (name and tonnage). The second interface will be a listing of existing ships with fields for the user to select and edit (see Figure 1):
Figure 1. Ship form

Figure 1 shows how the form generated by jpa2web looks. Note the three available
icons: one to create a new ship, one to list all ships (see Figure 2) and one to remove a persisted ship. The OK button will persist the ship in the database. Observe that because the ID field is a GeneratedValue, it appears as disabled.
Figure 2 shows the second generated Web page that lists existing ships. The user can click on a ship to make the previous form for editing the ship's details appear.
Figure 2. Ship listing

Classes referencing other classes
A more complex case arises when objects reference other objects from a different class. This is the case with Cabin.java, which has a ManyToOne relationship with Ship.java, as well as simple attributes (see Listing 2):
Listing 2.
Cabin.java
package com.titan.domain;
import javax.persistence.*;
@Entity
public class Cabin implements java.io.Serializable
{
private int id;
private String name;
private int bedCount;
private int deckLevel;
private Ship ship;
@Id @GeneratedValue
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getBedCount() { return bedCount; }
public void setBedCount(int count) { this.bedCount = count; }
public int getDeckLevel() { return deckLevel; }
public void setDeckLevel(int level) { this.deckLevel = level; }
@ManyToOne
public Ship getShip() { return ship; }
public void setShip(Ship ship) { this.ship = ship; }
public String toString() {
return name;
}
}
|
The jpa2web tool generates a form similar to that of Ship.java, but with a way to connect a given cabin to a particular ship.
This is done by a button that opens a modal for the user to select the desired ship. Figure 3 shows the generated form and Figure 4 shows how the modal dialog opens while selecting the ship. ZK's ease with handling modal dialogs makes it a really convenient technology to use.
Figure 3. Cabin form

Figure 4. Choosing the ship

Classes with higher multiplicities
Let's look at a more complex example now. What about classes that have different multiplicities? This is the case of the Customer.java class (see Listing 3), which simultaneously holds OneToOne, ManyToMany, and OneToMany relationships with other classes (namely CreditCard, Phone, and Reservation, respectively).
Listing 3.
Customer.java
package com.titan.domain;
import javax.persistence.*;
@Entity
public class Customer implements java.io.Serializable
{
private int id;
private String firstName;
private String lastName;
private boolean hasGoodCredit;
private Address address;
private Collection<Phone> phoneNumbers = new ArrayList<Phone>();
private CreditCard creditCard;
private Collection<Reservation> reservations =
new ArrayList<Reservation>();
@Id @GeneratedValue
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public boolean getHasGoodCredit() { return hasGoodCredit; }
public void setHasGoodCredit(boolean flag) { hasGoodCredit = flag; }
@OneToOne(cascade={CascadeType.ALL})
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
@OneToOne(cascade={CascadeType.ALL})
@IndexColumn(name="INDEX_COL_CC")
public CreditCard getCreditCard() { return creditCard; }
public void setCreditCard(CreditCard card) { creditCard = card; }
@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.EAGER)
@IndexColumn(name="INDEX_COL_PHON")
public Collection<Phone>getPhoneNumbers() { return phoneNumbers; }
public void setPhoneNumbers(Collection<Phone> phones) {
this.phoneNumbers = phones;
}
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@IndexColumn(name="INDEX_COL_CUS")
public Collection<Reservation> getReservations() { return reservations; }
public void setReservations(Collection<Reservation> reservations) {
this.reservations = reservations;
}
public String toString() {
return getLastName()+","+getFirstName();
}
}
|
Figure 5 shows how the class in Listing 3 is rendered. This page has different areas, which we will examine individually.
Figure 5. Customer form

Let's take a look at the how the CreditCard relationship is rendered.
This case is similar to the one seen in the previous section with Cabin.java and Ship.java (ManyToOne), wherein a button can open a modal form. However, because the relationship in the case of Customer-CreditCard is OneToOne, opening a dialog to select an existing instance will not be suitable because each credit card number is exclusively associated to a particular customer. Instead, a CreditCard form dialog will open where the complete details of a new credit card are entered (see Figure 6):
Figure 6. Completing the CreditCard details

Customer-Phone generates a grid where the user enters new
phone number details. Pressing the Add Row button creates a new row to enter a new phone number.
Customer-Reservation: ManyToMany
The Add.. button adds a new reservation to the list box collecting the selected reservations with a chooser modal dialog. Figure 7 shows the completed form with sample phone numbers and reservations added:
Figure 7. Completing the customer phone details

At this point, you might not like the look of the generated windows. Two main problems are that the field labels appear as Java property names, and the order in which they appear looks messy. You can address these appearance problems with the jpa2web tool's custom annotations. Adding the MemberField annotations to the Cabin class (Listing 4), for instance, will render a better look to the form (see Figure 8). Compare the decorated version with the raw one shown in Figure 3. The titles now include meaningful names, and the order of the fields now makes more sense.
Figure 8. Decorated cabin form

Listing 4. Decorating annotations in
Cabin.java
@Entity
public class Cabin implements java.io.Serializable
{
@Id @GeneratedValue @MemberField(order=1,showName="ID")
public int getId() { return id; }
public String getName() { return name; } @MemberField(order=2,showName="Cabin Name")
@MemberField(order=2,showName="Number of Beds")
public int getBedCount() { return bedCount; }
@MemberField(order=3,showName="Deck Level")
public int getDeckLevel() { return deckLevel; }
@ManyToOne @MemberField(showName="Ship")
public Ship getShip() { return ship; }
....
}
|
Other decorating features include the ability to generate combo boxes instead of text boxes when there is a series of predefined values a given field can take. This can also be done using the MemberField annotation. Many other annotations can be defined to customize the look and feel of the generated windows.
The jpa2web application in action
Now that you understand the characteristics of the jpa2web application, it's time to take a look at it in action. Follow these steps to get the software working with Apache Tomcat:
- Download jpa2web from Sourceforge.
- Extract the distribution to a folder on your disk (referred to as [dir] from now on).
- Download Tomcat from the Apache site and install it on a folder (referred to as [tomcatdir] from now on).
- Copy the JAR files from [dir]/zklibs and [dir]/jboss_libs to [tomcatdir]/lib.
- Download your preferred JDBC driver and copy the .jar file into [tomcatdir]/lib.
- Write your domain model source files (JPA-annotated beans) under the [dir]/modelsrc folder.
- Modify the [dir]/templates/hibernate-cfg.xml file to connect to the database (see the following code for an example):
<hibernate-configuration>
<session-factory name="thefactory">
<property name="hibernate.connection.driver_class">
net.sourceforge.jtds.jdbc.Driver
</property>
<property name="hibernate.dialect">
org.hibernate.dialect.SQLServerDialect
</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.connection.url">
jdbc:jtds:sqlserver://127.0.0.1:1433/test</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password">*</property>
<property name="hibernate.max_fetch_depth">0</property>
<#list windows as win><mapping class="${win.mainClass.name}" />
</#list>
</session-factory>
</hibernate-configuration>
|
- Modify the [rootdir]/jpa2web-loader.xml file to contain the packages of files you are interested in generating.
- Modify the paths to Tomcat in the build-tomcat.xml ANT file and execute the default
target:
$ ant -buildfile build-tomcat.xml. - Ready! A WAR folder is generated with the Web application in the [dir]/dist folder and is also copied to the webapps dir of Tomcat. You can access the application at: http://localhost:8080/sampleapp.war (or similar).
Although it's beyond the scope of this article to explain in detail how the jpa2web generator works, here is a summary of the main ideas and method behind the generator engine.
The input is simple: a series of JPA-annotated classes. These source files are read and an internal representation — called a loader — is built of the beans and the relationships among them. In particular, jpa2web only implements an EntityLoader (which reads JPA annotations), but other loaders could be implemented (for example, to read from XML-mapping configuration files). This structure is then used to feed the generator, which also takes as input a series of FreeMarker templates (see Resources for more information on FreeMarker templates). The use of templates makes jpa2web very flexible in the way the windows will be generated. Figure 9 shows the stages of the process. The output of the generator is a WAR folder with a working Web application containing a window for each of the annotated beans found, as well as an index to choose among them.
Figure 9. Generation process

The simplified pseudo-code for the generator is as follows:
The generator algorithm
for each bean in the model:
-create a form window called fully.classified.className.zul:
for each simple field
if (field is String) render textbox
if (field is int/byte/short) render integerbox
if (field is boolean) render checkbox
if (field is double/float) render doublebox/floatbox
for each OneToOne member:
render a button that will open a form to create an instance of the destiny class
for each ManyToOne member:
render a button that will open a list to choose an instance of the destiny class
for each OneToMany member:
render a table with the details of the destiny class and buttons
to add and delete rows
for each ManyToMany member:
render a listbox with the elements mapped,
and a button that will open a list to choose an instance of the destiny class
-create a window called list.fully.classified.className.zul
which lists all of the instances
-add the annotated class to the mapping area of hibernate.cfg.xml
-add links to a menu bar with the two windows generated for this bean
|
The above algorithm is just one way the mapping can be made, there are various other alternatives and different solutions will work in different scenarios. The generation process itself could be adapted at runtime with further annotations.
Several other tools are available that generate Web application code based on some kind of input, and many are complete implementations of model-driven architecture (MDA). The jpa2web tool should be considered as a lightweight annotation-driven code generation tool for developers rather than an complete implementation of MDA.
Developers must deal with several issues to develop a generator that could be used in larger deployments. Models with complex directional graphs formed from the class model will obviously not be supported by jpa2web, especially if complex circular references exist. At the time of this writing, jpa2web does not support OneToMany and ManyToMany inside a OneToMany relationship (although this implementation is viable and could be included in the jpa2web roadmap). Nevertheless, further research must be done on how to generate the windows when an intricate model is presented. Probably the most evident situation where jpa2web would not be suitable is when creating Web applications that are more transactional in nature and where user interfaces do not map directly to the class model.
Regardless of its limitations, jpa2web is a useful tool in many scenarios. You can use it to quickly generate the Web interfaces for non-transactional elements just by having the annotated beans. You can also use it for testing by creating the necessary instances of objects in a database, thus avoiding verbose entity creation scripts. The output of jpa2web must be seen as a developing prototype rather than a final application. The generated code is relatively simple and modifying its behavior, as well as adding validations and extra processing, is easily understood. For larger-scale applications, however, the applicability of jpa2web is more limited in terms of transactions, security, concurrency, and multitier restrictions, but it can be integrated with a bit of extra work.
Future planned enhancements include supporting more complex domain models in terms of the interconnection between the elements, adding custom annotations to better specify the generated user interface, and the possibility of generating code from other Ajax toolkits such as Google's GWT, OpenLaszo, or Echo2. The input of the generator could also be something to extend, and maybe an XMI file could be used to enter a model. If you're interested in extending jpa2web or further exploring its capabilities, feel free to contact the author.
Learn
- Learn more about POJOs (Plain Old Java Objects).
- Explore Hibernate.
- Explore ZK.
- Read the book "Enterprise JavaBeans, 3.0" by Bill Burke and Richard Monson-Haefel (O'Reilly, 5th Edition, 2006).
- Learn about FreeMarker templates.
- Learn more about MDA (Model Driven Architecture).
- Read up on JSR-000220 Enterprise JavaBeans 3.0
- Learn about the ZK framework.
- Dive into a
ZK Live Demo.
- Take a look at
Red Hat Middleware, Hibernate hbm2ddl.
- Read about
AndroMDA, an Open Source MDA Generator.
- Get familiar with
Java annotations.
- Read about the Apache Struts Framework.
- Explore
JavaServer Faces technology.
- Read about the powerful
Spring Framework.
- The
Google Web Toolkit helps you build Ajax applications in the Java language.
- Read about OpenLaszlo, an open source platform for building rich Internet applications
- Read up on
Echo2.
Get products and technologies
- Download jpa2web from Sourceforge.
Discuss

Maximo Gurmendez graduated from the Facultad de Ingenieria, Montevideo, Uruguay. He is a software engineer and a Sun Certified Professional in Java Technologies. Recently, he has been working as a software architect for a large educational institution in Uruguay designing learning platforms and academic management intranets. His research interests include developing groupware and collaborative Web technologies. In addition to authoring jpa2web, Maximo has contributed to other open source initiatives such as MofEditor, CwmPlaza, and Ecademicus Webs. He also enjoys working as a musical director staging musical plays in Montevideo. Maximo has been selected as a Fulbright scholar in 2008 and will pursue a graduate degree in the U.S. in 2008.
Comments (Undergoing maintenance)





