Java Minimal Template Engine

Introduction

The Java project Minimal Template Engine is meant to fill the gap between simple string formatting with basic Java classes like String.format and complex template solutions like Velocity or StringTemplate.

It is complete but minimal in a sense that you can express everything you need in a template language including 'if' and 'foreach', but nothing else. Because of this it is small, easy to learn and clearly focused. It does not try to solve what Java can do better anyway.

It has no external dependencies (except when running in compilation mode), can be extended and configured in many ways and has barely 80k of code size. It runs in almost all environments including the Google App Engine.

Minimal Template Engine is

The model

Map<String,Object>

Nothing more to say.

The Language

The language is really simple and can be learned in no time. It is all about having a text with small island of expressions that expand to text or control the expansion of text fragments. Those expressions are enclosed in special characters which are freely configurable but are by default

Replacing variables

The simplest form of an expression is to expand an entry contained in the model to a string: ${name}

If your model contains complex objects and you want to expand a certain property or field you can use the "." notation to navigate to it like e.g. ${object.name} .

Renderer information

How a variable is eventually converted to a string is determined by renderers. There are renderers which are automatically called based on the type of the variable, but calling them is not part of the template langauage, but rather a matter of configuring them on the engine - which is described in the API section.

However, there are also so called "named renderers" which you can address by passing their name along with the name of the variable. You do this by adding a semicolon and the name of the renderer to the variable name. You can even pass format information in brackets.

For example this
${currentDate;date(yyyy.MM.dd HH:mm:ss z)}
would cause the variable called "currentDate" to be formatted with a renderer named "date". This named renderer would then be passed the format "yyyy.MM.dd HH:mm:ss z" along with the variable to be rendered. Named renderers know which types they support and are responsible to do the necessary conversion for them.

Conditional expansion

Sometimes you might want to display certain text or expand certain expression only when certain conditions hold. The minimal template engine provides you with an if-statement to do so.

${if condition}
  text displayed if condition holds
${else}
  text displayed if condition does not hold
${end}

The else-part is optional and the whole conditional block has to be terminated by the end-expression. If-expressions can be nested and conditions can be negated using the "!"-operator. You can also compare to a string constant using the "="-operator.

There are no other logical operators, i.e. you can not combine conditions using and or or. The reason is that this is a minimal language, expressions can be complex and conditions can be constructed in the Java model. You can either have a condition directly inside the model or you can build a processor that computes it and add it to the model.

The condition can be any object. It evaluates using these rules

Conditional shortcuts

For convenience reasons there are some shortcuts for the most commonly used conditional statements. The first shortcut works by supplying a default constant value which will be used in case the variable is undefined. You can specify such a default value in brackets. E.g.
${address(unknown)}
would be equivalent to
${if address}${address}${else}unknown${end}
The second shortcut works by wrapping a value, but only if it is defined. You can wrap a value by adding a prefix and a suffix separated by commas. This means
${<h1>,address,</h1>}
is essentially the same as
${if address}<h1>${address}</h1>${end}
To avoid ambiguities, both prefix and suffix must be supplied or none at all, but they can also be the empty string.

Loops (expanding more than one item)

If you want to expand all elements of a container you can use the foreach-expression.

${foreach container item}
  ${item}
${end}

In this example variable item is set to each element of the container and the body - i.e. the part between the foreach- and the end-expression - is expanded for each item in the container. The container can be anything that implements java.lang.Iterable or anything that implements java.util.Map or any array. If the container is a map we iterate over its entry set and the items will be of type Map.Entry. This means you can access its parts using ${item.key} and ${item.value}.

Loops can be nested and can also contain all kinds of other expressions. You are not able to specify a step or a start of end index.

Special variables

In certain cases you might want to change the way an item in a container shall be displayed depending on its position inside the container. One example is to have the rows in a table be displayed having an alternating format depending whether their row number is even or odd.

Current list of special variables

  1. first
  2. last
  3. odd
  4. even
  5. index

Special variables are suffixed by a _ followed by the name of the item variable. This means inside a foreach loop that has item as the item name there will be the variable first_item.

Example:

${foreach items item}
  ${if first_item}
    <em>${item}</em>
  ${else}
    ${item}
  ${end}
${end}

Separators

When displaying a list of items you might want to have a separator between each item. This will not work using a normal body as there shall be no additional separator after the last item. You can either solve this using special variables - explained in the previous section - or more easily using a separator. Such a separator is added into the foreach expression like this

${foreach container item , }${item}${end}

Suppose the container contains the items item1 and item2 then the formatted output looks like item1, item2.

Escaping

When you want to use the special character sequences literally you will have to escape them using a the backslash \. You can also escape the backslash by adding a second.

In Java this would be

and if you read your template from a file

API

API reference can be found here .