Code Levels¶
While typical code generators work with code at two levels (generator level and generated code level), the Wurbelizer operates at three levels:
- wurblet level: holds the code for the generator itself
- output level: the generated code
- source level: the application's source code.
A traditional, template-based generator works from the model towards the code: it owns whole source files and must know their names, structure and relationships.

The Wurbelizer inverts this perspective — from the code towards the model. Small generators, called wurblets, are embedded within the source files; the wurblet and the model are referenced from within the source itself, so the generator only needs to know how to produce a single aspect of the code.

The source code of the wurblet itself contains a mix of the first two levels. The third level is parsed and modified by the wurbler. The wurbler analyzes the source files and locates comment-, Java- and generated code sections. The comments, which are ignored by the Java compiler, are parsed for wurblet anchors, variables and so-called here-documents. Then the wurblets are applied and the generated code inserted or replaced within the guarded blocks of the source file. The wurbler repeats these steps until there is no more change (generated code could contain new wurblet anchors!) and finally writes back the source file to the filesystem (if there was any change at all).
The overall pipeline — the meta-language being plain Java — looks like this: the wurbiler compiles the wurblet sources into wurblets, which are loaded into a wurblet container and, together with the model resources, drive the generation back into the source files.

The three levels in one example¶
A real example from the Tentackle framework, which generates its persistence layer this way. All three levels are involved in producing two lines of code.
Source level. The entity NumberPool declares its model in a comment, as a
here-document:
/*
* @> $mapfile
* ...
* ## attributes
* String(30) name name the number pool name [key]
* String(80) realm realm pool realm, optional [MAPNULL]
* ...
* @<
*/
Wurblet level and output level. The ColumnLengths wurblet mixes the two. The Java
code between @[ and ]@ runs at generation time; the three lines in between are the
template that gets written out, with @( )@ extracting values from the wurblet level:
@[
for (Attribute attr: getEntity().getAttributes()) {
if ("String".equals(attr.getEffectiveDataType().getJavaType()) && attr.getSize() != null && ...) {
]@
/** maximum number of characters for '@(attr)@'. */
@(lead)@int CL_@(attr.getName().toUpperCase(Locale.ROOT))@ = @(attr.getSize())@;
@[
}
}
]@
Source level again. The wurbler merges the output into the guarded block below the
anchor in NumberPoolPersistence.java:
// @wurblet fieldlengths ColumnLengths
//<editor-fold defaultstate="collapsed" desc="code 'fieldlengths' generated by wurblet ColumnLengths">//GEN-BEGIN:fieldlengths
/** maximum number of characters for 'name'. */
int CL_NAME = 30;
/** maximum number of characters for 'realm'. */
int CL_REALM = 80;
//</editor-fold>//GEN-END:fieldlengths
The wurblet never learned which file it would write to, what that file is called or what else is in it. It was told only what aspect to generate; the anchor in the source decided the rest. That inversion is what the three levels buy you.
Further reading¶
- Source Level Syntax — what the wurbler parses at the source level
- Wurblet Level Syntax — mixing the wurblet and output levels