Abstract
This article outlines the architecture of a template based code generator.
Project
This was on my job at InLine, aka JFX, aka ObjectVenture. See Model-View-Feature.
My assignment
One of the parts of the system was a template based code generator.
Challenges
Our tool needed to support several meta-models that required source code generation. Among those models was what we called Extended-J2EE, which expanded the J2EE programming model with such concepts as Relationship, Event, Constraint, ValueObject etc. Another was an abstract model that was based on Patterns. Each Pattern was represented by a collection of templates for code generation as well as Features (again, see Model-View-Feature. My job was to design and implement the foundation for this part of the system.
Solution
I defined a scripting language, JCML, that would be used to capture source code templates. A template consisted of items linked to Features of the model. Plug-ins could supply their additions or replacements for the default templates. The JCML interpreter that I developed would reconcile possible conflicts between different suppliers of code generation scripts and perform the actual code generation. The interpreter was invoked by implementations of corresponding Features or FeatureSets.
Here's an example of a JCML script. It is the default template for a ValueObject, which is a regular JavaBean that mimics the API of an EJB EntityBean. It actually produces code for both the interface of the ValueObject and its implementation.
Variables mentioned in the template: className, attributeList etc. are properties of the controlling Feature.
<?xml version="1.0"?> <jcml package="com.inline.j2ee.enhanced" model="J2EE"> <feature type="ejb1.1-valueObject"> <use-if path="../codeStyle" value="standard"/> <item name="interface"> <copyright/> <s-package-declaration>className</s-package-declaration> import java.io.Serializable; import java.util.*; /** * <s-unqualified-name>className</s-unqualified-name> is an * object that can hold a data snapshot of the <s>beanName</s> * EJB. * * @author <author/> * @version <version/> */ interface <s-unqualified-name>className</s-unqualified-name> { <for var="a" path="attributeList"> <if-equal path="a/included" value="true"> <then> public <s>a/type</s> <s>a/getterName</s>(); <if-equal path="a/editable" value="true"> <then> public void <s>a/setterName</s>( <s>a/type</s> <s>a/name</s>); </then> </if-equal> </then> </if-equal> </for> } </item> <item name="implementation"> <copyright/> <s-package-declaration>implClassName</s-package-declaration> /** * <s-unqualified-name>implClassName</s-unqualified-name> * is an implementation of the ValueObject interface * <s>className</s>. */ public class <s-unqualified-name>implClassName</s-unqualified-name> implements <s>className</s> { <for var="a" path="attributeList"> <if-equal path="a/included" value="true"> <then> private <s>a/type</s> <s>a/name</s>; </then> </if-equal> </for> <for var="a" path="attributeList"> <if-equal path="a/included" value="true"> <then> public <s>a/type</s> <s>a/getterName</s>() { return <s>a/name</s>; } public void <s>a/setterName</s>( <s>a/type</s> <s>a/name</s>){ this.<s>a/name</s> = <s>a/name</s>; } </then> </if-equal> </for> } </item> </feature> </jcml>
JCML was used successfully to implement the Extended J2EE model as well as Patterns. After I left Inline/JFX, Bill Willis and others extended JCML with PCML (Pattern Code Markup Language).
[UPDATE: Feb 2021. At Google I used a template system that follows a similar paradigm, Google Closure Templates, or Soy. See some examples for comparison. FTR, I had nothing to do with the creation of Soy.]