Template-Based Code Generation with Apache Velocity, Part 1

Most of the real-world code generators, both commercial and open source releases, use templates and template engines. In this article I'm going to discuss template-based code generation, explain basic concepts related to templates and transformations, and demonstrate the huge benefits they can bring in code generation. Then, I'll implement a simple code generator in Java that uses Velocity, an open source template engine provided by Apache. The generator takes an XML representation of classes and data members and generates the Java code to define them. The generation process will be driven by a template that encapsulates the syntax of the target programming language. You will see how to change the template to generate different types of source code.

Templates and Transformations

Template-based transformations are ubiquitous in the software development world. A wide number of tools use templates to transform data from a format to another. For example, XSLT is the standard way to perform XML document transformations based on templates that are written according to the eXtensible Stylesheet Language. Figure 1 shows the four components involved in a template-based transformation process. They are:

Data Model: Contains data, organized in a specific structure, that have to be transformed.

Template: Formats the data model into the output code. It contains references to entities belonging to the data model.

Template Engine: The application that performs the transformation. It has the input data model and the template, and produces output by replacing the template internal references with real data coming from the model.

Target: The result of the transformation process.

Figure 1. Template-based transformation

Let's consider the following simple example of a data model:

#person.txt
$name=John
$surname=Smith

This is a text file containing a first name and a surname: "John Smith." We want to transform the format of those data according with the following template:

#person.template
Hello, my name is $name and my surname is $surname

The template is also a text file; it contains two references, $name and $surname, to data present into the model.

If the template engine is an application called transform, then you may execute it, passing the data model and the template described above:

> transform person.txt person.template

The result will be:

Hello my name is John and my surname is Smith

The template engine replaced the labels $name and $surname with the real data coming from the model: "John Smith."

Note: The most important aspect about a template-based transformation is that you can change the final representation without touching the application performing the transformation. The only thing you have to modify is the template. For proof, let's consider the following template:

Template-based Code Generation

The code generation process is obviously a transformation process. The data model contains information about the system entities you want to generate, and the template represents the syntax of the target programming language.

Another small example will show the language-portability benefits of code generation. Here is a data model:

#student.txt
$name=Student
$base=Person

It represents a name of a class (Student) and its base class (Person). In order to generate Java code to declare the Student class, you can use this template:

#javaclass.template
public class $name extends $base {
}

The transform application, having those data model and template as input, returns:

public class Student extends Person {
}

which is the definition of the Student class. Thus, we generated code starting from a data model and a template.

To build an interface, we alter the template slightly:

#javainterface.template
public interface $name implements $base {
}

That template drives the engine to produce:

public interface Student implements Person {
}

The engine now generates Student as an interface rather than a class. The good news is that we didn't touch the data model or template engine.

And to show the language portability aspects, we will change the template to build C++:

#cpp.template
class $name : public $base
{
}

The result will be:

class Student : public Person
{
}

Which is the definition of the Student class in C++. Without altering the data model or the template engine, we generated code in another language! That's a very important aspect -- a well-designed, template-based code generator can generate code for different languages by using different types of templates. This is also why a well-designed object model contains no language-specific details.