wurblets and in this directory create another pom.xml with the following contents:
4.0.0 com.example wurbelizer-tutorial 1.0-SNAPSHOT org.example wurblets 1.0-SNAPSHOT org.wurbelizer wurbelizer ${wurbelizer.version} org.wurbelizer wurbelizer-maven-plugin wurbile
The execution goal wurbile translates the wurblet source code to compilable Java and a resource file holding strings.
The wurbelizer can load and execute any Java class that implements the interface org.wurbelizer.wurblet.Wurblet.
The dependency above not only provides this interface but also 2 abstract classes to make the developer’s life easier:
org.wurbelizer.wurblet.AbstractWurbletthat implementsorg.wurbelizer.wurblet.Wurbletorg.wurbelizer.wurblet.AbstractJavaWurbletthat extendsorg.wurbelizer.wurblet.AbstractWurblet
To define the properties of the DTO we need some model which can be parsed by the wurblet. For this tutorial we’re using a very simple format with one line per property consisting of:
- the Java type, e.g.
String - the property’s name
- some optional comment
In src/main/java/com/example/wurblets please create file DTOWurblet.java with the following content:
package com.example.wurblets;
import org.wurbelizer.wurbel.WurbelException;
import org.wurbelizer.wurbel.WurbelHelper;
import org.wurbelizer.wurblet.AbstractJavaWurblet;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* Base class for the {@code @DTO}-wurblet.
*/
public class DTOWurblet extends AbstractJavaWurblet {
/**
* DTO property.
*/
protected class Property {
private final String type; // the java type
private final String name; // the property name
private final String comment; // the comment
public Property(String type, String name, String comment) {
this.type = type;
this.name = name;
this.comment = comment == null || comment.isEmpty() ? "the " + name + " property" : comment.trim();
}
public String getType() {
return type;
}
public String getName() {
return name;
}
public String getComment() {
return comment;
}
public String getGetterName() {
return ("boolean".equals(type) ? "is" : "get") + firstToUpper(name);
}
}
protected String filename; // filename of the here-doc holding the model
protected List<Property> properties; // the DTO properties
@Override
public void run() throws WurbelException {
super.run();
if (getContainer().getArgs().length == 0) {
throw new WurbelException("usage: @wurblet <guardname> DTO <filename>");
}
filename = getContainer().getArgs()[0];
properties = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(WurbelHelper.openReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty() && !line.startsWith("#")) {
StringTokenizer stok = new StringTokenizer(line);
String type = null;
String name = null;
StringBuilder comment = new StringBuilder();
while (stok.hasMoreTokens()) {
String token = stok.nextToken();
if (type == null) {
type = token;
}
else if (name == null) {
name = token;
}
else {
if (comment.length() > 0) {
comment.append(' ');
}
comment.append(token);
}
}
if (type == null || name == null) {
throw new WurbelException("property line too short: '" + line + "'");
}
properties.add(new Property(type, name, comment.toString()));
}
}
// validate
for (Property property : properties) {
if (property.getType().isEmpty()) {
throw new WurbelException("missing property type");
}
if (property.getName().isEmpty()) {
throw new WurbelException("missing property name");
}
}
}
catch (IOException ex) {
throw new WurbelException("reading model " + filename + " failed", ex);
}
}
private String firstToUpper(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
Next, in src/main/wurblets/com/example/wurblets create the file DTO.wrbl with the following content:
@{package com.example.wurblets}@
@{import java.util.*}@
@{import java.io.*}@
@{import org.wurbelizer.wurbel.*}@
@{import org.wurbelizer.wurblet.*}@
@{import org.wurbelizer.misc.*}@
@{extends DTOWurblet}@
@{args}@
@{comment
Creates code for a data transfer object.
}@
@[
private void wurbel() throws WurbelException {
// create declarations
for (Property property: properties) {
]@
private final @(property.getType())@ @(property.getName())@; // @(property.getComment())@
@[
}
// create constructor
]@
/**
* Creates a @(getClassName())@.
*
@[
StringBuilder args = new StringBuilder();
for (Property property: properties) {
if (args.length() > 0) {
args.append(", ");
}
args.append(property.getType()).append(' ').append(property.getName());
]@
* \@param @(property.getName())@ @(property.getComment())@
@[
}
]@
*/
public @(getClassName())@(@(args)@) {
@[
for (Property property: properties) {
]@
this.@(property.getName())@ = @(property.getName())@;
@[
}
]@
}
@[
// create getter
for (Property property: properties) {
]@
/**
* Gets @(property.getComment())@.
*
* \@return @(property.getComment())@
*/
public @(property.getType())@ @(property.getGetterName())@() {
return @(property.getName())@;
}
@[
}
}
]@
As already mentioned in the introduction the wurbelizer’s template language is Java with a few syntax extensions. The extensions are necessary to separate the template level from the generated code level:
@[to switch to template level]@to switch to code level@(...)@to extract a value from the template level (within code level)
The other lines at the beginning of the wurblet source are pretty self-explaining. Notice that the wurblet extends DTOWurblet.
Execute mvn clean install in the parent directory. This will invoke the wurbiler (wurblet compiler), compile the Java code and create a jar file.
In the next chapter we will use the wurblet to generate code for a DTO.