Fork me on GitHub schema

Snippetory, templating platform

Snippetory is an extensible templating solution for the JVM. This rises the question:

There are so many template engines. Why yet another one?

Considering general template engines (vs bound to XML) I think there is great variety in two groups of solutions. There are script based template engines with a more or less complete language to fill out them selves with the data they get. The other group are the very simple projects with great separation of templating and logic, but almost nothing else.

Snippetory tries to get the best of both wolrds. It provides all the features a modern templating solution should provide. And it moves the binding code out of the template, so all the great java tool set can be used with it.

Snippetory provides this key features:
Passive templates
Templates syntax only consists of locations, regions and some meta data. Separate the data binding logic from the template code to
  • make the template simpler, shorter and, more readable
  • make the template as well as the logic more re-useable.
  • to ease the structuring of the logic
  • gain the full power of java when writing logic.
    • Testability
    • Organize in classes & methods
    • Quality analysis with Checkstyle, Findbugs and the like
    • Great tooling with refacforing support
    • Hard typed
Plug-able syntax
By using a syntax that fits the template code it's possible to validate the template before writing the logic. However, for java code templates one needs obviously another syntax than HTML in order to achieve this... read more
Configurable formatting chain
In many cases the template is a great place to define how values are presented as this affects the look of the output. Formatting includes type conversion, string manipulation and, even some view logic can be implemented by it... read more
Extensible escaping
To ensure data is presented the way it is saved, it's sometimes necessary to escape it according to the actual output format. To minimize the definition effort and support consistency encoding is inherited down the template tree and can be overwritten where needed. The Snippetory template engine ships with a number of predefined encodings... read more
Integrated repository
Repositories are used to separate the location of usage and the location of storage. This allows one to organize the template code in the way it's useful, not necessarily the way the technology dictates. Of course, in most cases you want to store the code where it's used. However this is a bit difficult, whenever you reuse it. With Snippetory you can use any region where you need it. No additional effort needed.

Snippetory is a simple, Java based template engine. Java based means, that all logic is written in Java. There's no embedded scripting language. This makes templates short and readable, focused on being a template! In many cases it is possible to write templates that can be used like output files. I.e. view HTML templates in a browser and test the javaScript, compile Java templates and so on.

Snippetory has a second important trait: an integrated repository for organizing and reusing the template code in a formerly unexperienced manner. Logic and presentation are separated by an opaque abstraction layer. So, let's start with the omnipresent 'Hello World':

Repo.parse("Hello {v:who}").set("who", "World").render(System.out);

So what do we see?

  • WOW Template definition, template creation, data binding and output in a single line. The fluent interface allows really compact code!
  • The overhead is minimal. No dependencies, no long initialization. Just create the template and go for it!

OK, let's calm down a bit. The sense of Hello world is being simple and it was simple, so mission completed.

To get a step further I thought of somewhat more complex. As this is not a tool for the simple things I choose something really complicated:
Generating Java source based on reflection!
OK, let's say we bind a complex data type the template. However, I would like to have your attention on the template code. Even though it's not too much it introduces two addition concepts:

The region definition
Simply a bunch of code to be omitted, repeated or replaced.
Additional meta data
In our case the delimiter attribute. Delimiters tend to increase code complexity a bit, because they have to be omitted on one iteration. So meta data is used for some typical logic and formatting

Locale

Another thing that might confuse is the locale parameter. Many template engine don't offer a standard way to handle the locale. I don't understand that. Template engines are often used in user interface and has to convert types to strings. And converting a date to a string to a date is language dependent.

Syntax

Finally we use another Syntax here. This allows the template to compile as java code.

The template:

///       mock                 mock                  meta data     repeated area
///      |----|              |------|              |------------| |-------------|
/*$type(*/void/*)*/ /*$name(*/render/*)*/(/*$param(delimiter=', '){$type param$i}$*/);

The binding code:

  Method def = Template.class.getMethod("render", Template.class, String.class);
  
  // Repo provides methods to read this from class path, file, Reader and so on.
  // The typical workflow consists of getting the template data, configure the 
  // context and finally parse to materialize the template object.
  Template method = Repo.readResource("method.tpl").syntax(FLUYT_CC).parse();
  
  // bind parent data
  String typeName = def.getReturnType().getSimpleName();
  method.set("type", typeName);
  method.set("name", def.getName());
  
  for (int i = 0; i < def.getParameterTypes().length; i++) {
    String paramType = def.getParameterTypes()[i].getSimpleName();
    
    // bind child data -> the builder interface helps to have concise code
    method.get("param").set("type", paramType).set("i", i).render();
  }
  method.render(System.out);

Output:

void render(Template param0, String param1)

Why use Snippetory?

It's simple!

Snippetory moves the binding code out of the template, and relies on your JVM language for binding. This massively reduces the number of additonal constucts Snippetory has to introduce. No variable declarations, no macros, no directives, no path navigation. Only regions, locations and a little bit meta data.

It's not primitive.

Even though there are a number of simple template engines around, they tend to get stuck when things get a little more complicated because the abstraction layer is simple, too. All the escaping and formatting is done out of context. Or to be honest, in many cases escaping is omitted.

It's a repository

It can be used some data belonging to your output. For instance in our pre-localized email template, we can store the subject. Or having many outputs in one file, maybe if one wants get SQL statements out of source. When ever there is a bunch of texts to handle Snippetory may help.

It's general

Snippetory is not bound to any output format. It has build-in support for HTML, other XML, formatted, human readable plain text, fixed field length and limited code generation support. I would even say it's best of bread in being general.

It's a text handling platform

There are many things one can replace while still taking advantage of others. However, when getting into it, it looses quite a bit of it's simplicity. But it enables a number of uses I never thought of.

It java based

On first sight omitting an own scripting language looks like a disadvantage. It's so inflexible, in XY I can change without so much more without changing java. Mh, what exactly means: Without changing java??? If this is important how cute is Assembler? One can do so much without changing any java. Of course, to replace a JSP page you need some java AND a template. However the combination gains the full power of java. I wrote a web reporting solution. And it wouldn't have worked without that feature.

Enjoy!

Bernd Ebertz

Head, Founder and chief technology evangelist of
jproggy.org
Java, and all Java-based marks are trademarks or registered trademarks of Oracle.
This site is not affiliated in any way with Oracle.