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.AbstractWurblet
that implementsorg.wurbelizer.wurblet.Wurblet
org.wurbelizer.wurblet.AbstractJavaWurblet
that 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.