Passive Code Generators
The advantages of passive code generators are well known to developers thanks to the popularity of code wizards used by virtually all IDEs. Such are the benefits of passive code generators that few developers would consider using an IDE that did not number code wizards among its features.
Passive code generators are typically template driven. The template is a parameterized blueprint of the code to be produced. The generator is supplied with the necessary parameters, and the code generator undertakes a basic parameter-substitution process on the template in order to generate the required output.
Passive code generators are simple and therefore easily written. Open source tools are available that make the task of developing passive code generators all but trivial. One such offering is Velocity from the Apache Software Foundation.
Velocity is a powerful Java-based template engine. Although its use is primarily aimed at the generation of dynamic content at runtime, it is also an effective tool for writing your own code generators. Full details of the Velocity template engine can be obtained from http://jakarta.apache.org/velocity.
Velocity can be used to write all manner of specialized code generators for your project, including supplementing the code wizards already provided by your favorite IDE.
Here is an example of a rudimentary code wizard written using Velocity. This simple generator accepts a series of parameters, such as class name and author, and outputs a Java file as the result.
Code Generation with Apache Velocity
Velocity is a template-driven engine, so the first task is to define a template for our class wizard. Listing 6-1 shows the basic template on which our newly generated classes are based.
Example 6-1. Velocity Template
wizard_template.vm /* * Created by: $author * */ public class $class extends $base { #if ($add_ctor == true) public $class() { } #end #if ($add_main == true) public static void main(String[] args) { } #end } // $class
The template is defined using the Velocity Template Language (VTL), a special markup language specifically designed for working with templates. The example illustrates the use of the two parts of VTL, references and directives.
VTL references are the parameterized part of the template and are substituted for actual data when the Velocity engine is run. A VTL reference is any string commencing with the $ character. The example includes five references: $class, $base, $author, $add_ctor, and $add_main.
VTL directives are used for controlling the generation of output. The VTL notation specifies that directives start with the # character. From the template shown in Listing 6-1, VTL directives have been used to determine if either a constructor or a main method is required for the generated class. This is accomplished using the #if directive combined with the references $add_ctor and $add_main.
Table 6-1 lists the available VTL directives.
Table 6-1. VTL Directives
Directive |
Description |
Example |
#foreach |
Iterates through a list of objects. |
#foreach ($item in $list) $item.Name #end |
#set |
Assigns a value to a reference. |
#set ($myRef = $yourRef) |
#if |
For constructing conditional statements. |
#if ($expenditure > $income) |
#else |
Save |
|
#elseif |
#end |
|
#parse |
Renders another Velocity template. |
#parse ("mail.vm") |
#include |
Renders the named files without parsing. |
#include ("footer.txt") |
#macro |
Defines a new VTL directive based on existing directives known as a Velocimacro (VM). |
#macro (vmmacro $arg1 $argn) #if ($arg1 > $argn ) Show $arg1 #end #end |
#stop |
Stops execution of the template engine. |
#if ($condition) #stop #end |
## |
Comments. |
## Single |
#+ |
#* |
|
+# |
Multi line *# |
With our template defined, the next task is to map actual data to the references in the template. Listing 6-2 shows the implementation for the code generator.
Example 6-2. The ClassWizard Code Generator
// ClassWizard.java import java.io.FileWriter; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; public class ClassWizard { public static void main(String[] args) { // Set the name for the new class // String className = "MyNewClass"; try { // Rev up the velocity engine // VelocityEngine engine = new VelocityEngine(); engine.init(); // Get the template from the engine // Template template = engine.getTemplate("wizard_template.vm"); // Create context and add data // VelocityContext context = new VelocityContext(); context.put("class", className); context.put("author", "John Smith"); context.put("base", "MyBaseClass"); context.put("add_ctor", new Boolean(false)); context.put("add_main", new Boolean(true)); // Generate output from the template // FileWriter writer = new FileWriter(className + ".java"); template.merge(context, writer); writer.flush(); } catch (Exception ex) { System.err.println(ex); } } } // ClassWizard
The code generator initializes an instance of the Velocity engine and loads in the template. Data is mapped to each VTL reference defined in the template using a VelocityContext. Once all references have been bound to data, the VelocityContext is merged with the Template instance to produce the output file.
The output generated after compiling and running the code is shown in Listing 6-3.
Example 6-3. Generated File
MyNewClass.java /* * Created by: John Smith * */ public class MyNewClass extends MyBaseClass { public static void main(String[] args) { } } // MyNewClass
So as not to obscure the example, the parameters supplied to the Velocity context were hardwired in the code. This is less than ideal for a generic code wizard. I will leave it as an exercise for you to supply the code generator with data for binding with the template at runtime. Parameters could be supplied as command-line arguments, from a file, or from a swing-based user interface.
Benefits of Passive Code Generation
Passive code generators are a productive tool for getting the developer off to a good start. They can provide an extensive head start, and they range from generating small classes, as shown in the example, to generating entire object hierarchies.
When generating from a template that embodies software engineering best practices, the code they generate is consistently of a high quality. Where the code generator is developed inhouse, it is expected that the resulting code will always comply with company standards, assuming of course that this holds true for the template.
As a final note, not all passive code generators are code wizards. Another possible use of a passive generator is for migrating systems between platforms. One company I encountered used a code generator extensively for converting Oracle Forms applications to Java. The company initially began as part of a larger IT department, when the development team was first charged with the task of porting a large Oracle Forms application to Java. The application to be ported was extensive, and the conversion effort was expected to tie up a large team over a long timeframe. Due to the high costs of a manual approach, the company instead decided to invest its energy into the development of a code generator to automate the initial conversion effort.
The generator they produced was unable to convert every line of code. However, it was able to convert enough of the application that only a small development team was needed to fix up those areas too complex to convert automatically.
The project was completed successfully, and the development team went on to offer its services to other organizations undertaking similar conversion exercises. Thanks to the code generator developed from the previous project, the company was able to leverage this for considerable competitive advantage when competing for Oracle Forms conversion work. From a sales perspective, it could tick all the right boxes: do the job quicker, to a high standard, and at a lower cost.