Enums are one of the nice new features in Java 5. For various reasons many of us don't have access to Java 5 at work, so we make do with homegrown versions of enums. Joshua Bloch's Effective Java has a nice section (Item 21) about using enum classes in Java. If you follow Mr. Bloch's advice and write enum classes, you've no doubt noticed there is some boilerplate code involved. For example, enum classes that implement Comparable need to implement a compareTo method. The differences between two classes is slight but (obviously) significant:
// class Day
public int compareTo(Object obj) {
return this.ordinal - ((Day) obj).ordinal;
}
// class Week
public int compareTo(Object obj) {
return this.ordinal - ((Week) obj).ordinal;
}
It would be nice to have a code generator that produces Java code with the proper values where needed from a template that contains all the tedious code. My first inclination was to read in a template file and replace certain paramters using regular expressions:
(line =~ /#classname/).replaceAll(classname)
It worked fine, but I wanted to use $ to designate a parameter but it is a special character in regex I couldn't use it in the template. (Sidebar: I don't use regex often so I'm no expert, but I thought that /\$classname/ should have worked but it didn't.)
Enter the Groovy Template Engine. The template engine alleviates the pain of typing boilerplate code by processing a template that contains the repetitive code and replaces parameters with unique values. To demonstrate, let's write some Groovy code.
First the template for the compareTo method is a GString that looks like:
def compareTo = '''
public int compareTo(Object obj) {
return this.ordinal - (($classname) obj).ordinal;
}
'''
Next we'll create a template engine:
def engine = new groovy.text.SimpleTemplateEngine
Now the fun part:
["Day", "Week"].each {
def binding = ["classname":it]
println engine.createTemplate(compareTo).make(binding)
}
The engine uses a map of key-value pairs where the key name matches the name of the template parameter, in this case, "classname" and the value is the value that replaces the template parameter. Running this little snippet produces the following:
public int compareTo(Object obj) {
return this.ordinal - ((Day) obj).ordinal;
}
public int compareTo(Object obj) {
return this.ordinal - ((Week) obj).ordinal;
}
That's all there is to it. You can download a complete enum generator here.
Concerning your regex problem, this works with JSR-06:
new File("test.java").eachLine {
line ->
println( (line =~ /\$classname/).replaceAll("ANewClassname") )
}
Having a template file like this:
public $classname {
$classname() {
}
}
Comment by Guido Schoepp — July 15, 2006 @ 3:36 am
Nice! When I started using Groovy, I toyed with some code generation scripts using GRAM, but I didn’t know about the templates. Thanks!
Comment by Andres Almiray — August 20, 2006 @ 5:55 pm
It’s a real shame the Groovy template engine doesn’t ‘fail-fast’, what a retarded design decision that was. Why does this test pass?
@Test
public void groovyTemplatesAreRetarded() throws Exception
{
SimpleTemplateEngine engine = new SimpleTemplateEngine();
Template template = engine.createTemplate(“${foo}”);
Writable w = template.make();
}
Stupid!
Comment by Malcolm Sparks — November 24, 2007 @ 10:21 pm