Generate JavaBean classes dynamically with XSLT

Use the XSLT processor as a powerful source code generator

In some commercial software projects, you cannot afford to cast in stone the structure of business objects. For example, different companies may have different and even mutually exclusive requirements for Product bean properties. Without a proper framework in place, you may end up spending long hours customizing all your data structures, including classes, database tables, DTDs (document type definitions), and so on, for every new customer. Needless to say, you may soon find yourself with a pocketful of parallel software versions and a maintenance headache. How do you ensure that your design is flexible enough to satisfy varying business requirements without a need to do extra coding each time those requirements change?

In this article, I lay a foundation for a simple framework I successfully employed to build truly adaptive systems. It is based upon dynamic source code generation from a class's metadata maintained in a data dictionary. In the process, you'll get a refresher on JDBC (Java Database Connectivity) and JSPs (JavaServer Pages), and you'll also learn to generate source code with one of today's most fascinating XML-related technologies, XSLT (Extensible Stylesheet Language for Transformations).

Short design session

First, let's set up a simple hypothetical project to which we can apply all the wonderful techniques discussed here. The project will be an application geared towards a vertical market that has a

Product

concept in its business vocabulary. You can pick your own favorite business domain -- financial services, online retailing, or maybe even technical training; anything that uses a product. The system architecture is not a constraint either; it may range from a standalone application to a distributed

n

-tier system. In this article, we will concentrate on the business object design issues equally applicable in the wide array of different projects.

Since we won't design this application for a particular customer, we must make sure we know the business well enough to cover the most complex cases. To achieve that, we hire the best domain experts, run a few CRC (class-responsibility-collaboration) sessions, chart several use cases, and eventually assemble a clear understanding of a Product concept, among many others. With that information on hand, we can build a conceptual business domain model that includes our perfect Product bean depicted below:

Product

code: int

name: String

testedOnAnimals: boolean

availableSince: java.util.Date

This is roughly what we do in real projects before the actual coding, especially if we adhere to a good software development process.

Traditional implementation

Now we can implement the construction phase, where we craft the Product bean's Java code. In Java terms, a bean is a reusable component from either the JavaBean or the Enterprise JavaBean (EJB) frameworks. Despite many significant differences between the two kinds of beans, there are also similarities. For example, they share the notion of a bean property. The bean property is based on the standard Java naming convention for the pair of accessor methods. Thus, if the bean has a nonindexed property code, it is assumed that it provides the writer and reader methods setCode() and getCode(), respectively. The reader method for the boolean type property would be isCode(). For an indexed property, the bean is assumed to possess two sets of setCode() and getCode() methods, one of which would be indexed while the other would deal with the whole array. The java.beans.Introspector uses the same rule set applied in reverse to dynamically analyze the bean class and discover the set of exposed bean properties on the fly.

The properties concept becomes particularly handy when you need to map a business object to a data repository, like a database table or an XML document. Similarly, it helps at the presentation tier too. For example, the JSP API provides a mechanism for mapping HTTP request parameters to the bean's properties. The following action saves a tremendous amount of routine coding by magically initializing bean properties from the matching fields in an HTML form:

<jsp:setProperty name="myBean" property="*"/>

Ultimately, a bean is just a Java class that adheres to a set of well-defined rules. Let's use the simpler bean type, JavaBean, for our project, which will adequately demonstrate the points made here. Later you may apply these techniques to EJB components as well.

Now we can say that our Product bean has the integer property code, the String property name, the boolean property testedOnAnimals, and the date property availableSince. As we might expect, the bean translates to Java as Listing 1 shows:

Listing 1. Product.java

public class Product {
  private int code;
  private String name;
  private boolean testedOnAnimals;
  private java.util.Date availableSince;
  public Product() {}
  public int getCode() {
    return code;
  }
  public void setCode(int newCode) {
    code = newCode;
  }
  public void setName(String newName) {
    name = newName;
  }
  public String getName() {
    return name;
  }
  public void setTestedOnAnimals(boolean newTestedOnAnimals) {
    testedOnAnimals = newTestedOnAnimals;
  }
  public boolean isTestedOnAnimals() {
    return testedOnAnimals;
  }
  public void setAvailableSince(java.util.Date newAvailableSince) {
    availableSince = newAvailableSince;
  }
  public java.util.Date getAvailableSince() {
    return availableSince;
  }
}

The pros and cons of traditional implementation

For this project, we've chosen a straightforward, fast, and inexpensive approach to building the Product bean. Certainly, we may extend it to EJBs as well. As a result, we will have a system that hopefully suits all possible scenarios within the business domain.

In most cases, we can get away with this approach. However, what happens if a new customer unexpectedly comes up with a different perspective on our carefully designed beans? What if we must add a new Boolean property y3KCompliant to the Product bean? Remember, we'd need to modify not only this particular bean's source code, but also all the relevant data structures, including BeanInfo classes, SQL statements, and perhaps some classes that belong to our application's view and controller parts. Worse yet, what if the customer wants permission to do all that without our help? Don't forget that when you deal with a real commercial business application, you likely have at least 100 different business objects. So, what if you must tune each object for every new customer? On the flip side, what once looked like a quick and easy solution appears to be a bottleneck.

One common solution adds extra properties to each business object, reserved specifically for the client's proprietary purposes. Let's try this tactic and add three extra properties for a few primitive types, as well as for the String and the Date types to our Product class:

Product

code: int

name: String

testedOnAnimals: boolean

availableSince: java.util.Date

num01: double

num02: double

num03: double

bool01: boolean

bool02: boolean

bool03: boolean

str01: String

str02: String

str03: String

date01: Date

date02: Date

date03: Date

Sometimes this solves the problem, but frankly it looks ugly and feels uncomfortable. From my years in software development, I've learned that a lack of inner comfort is a reliable sign of bad design. And really, how can we be certain that each type's three extra properties are sufficient? Moreover, those customers who never needed those extra properties will pay high price in the form of wasted table space. Can't we design a system that easily adapts itself to the different business requirements?

Code generation to the rescue

The problem we face resembles the situation in which a Website's static HTML content can no longer satisfy business demand. In that case, Web application developers use various technologies to deliver dynamic data-driven content. We need something similar that, instead of HTML, generates Java source code for our beans. This becomes our main objective now. Once we have an adequate solution, you can extend it to all other data structures involved in application customization. Assuming you have a proper application framework in place, you should be able to simply plug in the new code without any additional coding. If you can do that, then your clients will be able to perform such customization themselves -- if provided with a slick GUI interface, of course.

To benefit from the automatic code generation process, we need to feed it detailed bean descriptions. In other words, we need a repository that we can query for the class's metadata. This is similar to the idea of the database metadata we can obtain using the getMetaData() method of the java.sql.Connection interface from the JDBC API. In the RDBMS (relational database management system) world, such information is usually maintained through the data dictionary -- a set of system tables that completely describe the database structure.

In the OOAD (object-oriented analysis and design) world, UML (Unified Modeling Language) often expresses the class metadata. An increasing number of UML modeling tools provide forward-engineering facilities from UML to source code and vice versa. Even though I prefer to keep the UML model and the source code in synch, I am not satisfied with the level of control we have over the code-generation process with these kind of tools.

Another language used to describe metadata is, of course, XML. It has several features that make it particularly attractive for this task:

  • XML is platform and application independent
  • You can easily validate XML documents against a DTD or schema
  • XSLT stylesheet processors easily transform XML documents into any other format, including source code in Java, Smalltalk, or even C#

In fact, the XML Metadata Interchange (XMI) format developed by IBM, Unisys, Oracle, and other industry leaders is a common language for metadata interchange between modeling tools, as well as between the tools and metadata repositories. Though we could use it here, it probably would require another article as an introduction. Also, XMI is to some extent overkill for what we want to do. However, you should keep XMI in mind when you work on more sophisticated projects. Certainly all the techniques we discuss in this article will still be valid if you decide to employ XMI.

Before we continue, I would like to mention one interesting solution addressed in Mark Pollack's "Code Generation Using Javadoc" (JavaWorld, August 2000). Pollack and his team used simple Java classes to describe the metadata for complex classes. They took advantage of the Java compiler to check their model's integrity. Then they created a doclet for the javadoc utility included in the Java SDK. The doclet generated source code based on the information the javadoc dynamically obtained from analyzing these metadata classes. Although I give much credit to this team for its innovation and reuse of existing tools, we cannot use this approach in our hypothetical project. Someone still has to know how to code the metadata classes manually. This would be a hard sell to an average customer. Our objective is to build a framework that provides hands-free business object customization.

The game plan

In our solution, we will combine the best of existing techniques. We'll maintain the class metadata in the simple data dictionary that we design from scratch. A relational database is probably the most suitable tool for this purpose, for the following reasons:

  • It provides secure and reliable data storage
  • It is easy to build a user interface for data management
  • It puts no technological constraints on the tools that extract the data
  • It is part of most software projects anyway

Once we have the metadata in the data dictionary, we can use the XML metadata server to dynamically extract the information and present it as an XML document by HTTP request. By using HTTP, we remove any technological constraints on the XML metadata server implementation, although I do prefer using JSPs or the Servlet API to build a metadata server.

As soon as we receive the XML document's class metadata, we will employ a generic XSLT processor to transform the document into Java source code. In addition to the metadata, we also need an XSLT stylesheet, which includes the processing instructions that the XSLT processor needs to perform its transformation magic.

Once we have all the pieces in place, we just need to customize a bean class by tweaking a few records in the data dictionary, sending an HTTP request, and receiving freshly minted Java classes. Any customer could probably do this, since no programming is involved.

The following figure is a high-level sequence diagram that helps to visualize this game plan.

The game plan

Create a data dictionary

There is no standard data dictionary schema that we can borrow for our project. Every team designs one that suits its requirements best. Let's design a simple proof-of-concept data dictionary. Later, I'll elaborate on how to make it more sophisticated and suitable for a commercial project.

We need just two tables. The Beans table contains information about the bean classes, while the Properties table describes their properties. Below are the SQL statements that you can use to build these tables in the relational database of your choice:

1 2 3 Page 1
Page 1 of 3