Data-driven presentation templates for Java
Java HTML
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
jtemplate Update version number. Jul 27, 2018
.gitignore Update .gitignore. Jul 23, 2018
README.md Update version number. Jul 27, 2018
settings.gradle Replace Ant build with Gradle. Jul 23, 2018

README.md

Releases Maven Central

Introduction

JTemplate is an open-source implementation of the CTemplate templating system (aka "Mustache") for Java.

This guide introduces the JTemplate framework and provides an overview of its key features. The first section introduces the template syntax used by the CTemplate system. The remaining sections discuss the classes provided by the JTemplate framework for processing template documents.

Feedback

Feedback is welcome and encouraged. Please feel free to contact me with any questions, comments, or suggestions. Also, if you like using JTemplate, please consider starring it!

Contents

Getting JTemplate

JTemplate is distributed as a single JAR file that can be downloaded here. It is also available via Maven:

<dependency>
    <groupId>org.jtemplate</groupId>
    <artifactId>jtemplate</artifactId>
    <version>...</version>
</dependency>

Java 8 or later is required.

Template Syntax

Templates are documents that describe an output format such as HTML, XML, JSON, or CSV. They allow the ultimate representation of a data structure to be specified independently of the data itself, promoting a clear separation of responsibility.

The CTemplate system defines a set of "markers" that are replaced with values supplied by the data structure (which CTemplate calls a "data dictionary") when a template is processed. The following CTemplate marker types are supported by JTemplate:

  • {{variable}} - injects a variable from the data dictionary into the output
  • {{#section}}...{{/section}} - defines a repeating section of content
  • {{>include}} - imports content from another template
  • {{!comment}} - provides informational text about a template's content

The data dictionary is provided by an instance of java.util.Map whose entries represent the values supplied by the dictionary. For example, the contents of the following map might represent the result of some simple statistical calculations:

{
  "count": 3, 
  "sum": 9.0,
  "average": 3.0
}

A template for transforming this data into HTML is shown below:

<html>
<head>
    <title>Statistics</title>
</head>
<body>
    <p>Count: {{count}}</p>
    <p>Sum: {{sum}}</p>
    <p>Average: {{average}}</p> 
</body>
</html>

At execution time, the "count", "sum", and "average" markers are replaced by their corresponding values from the data dictionary, producing the following markup:

<html>
<head>
    <title>Statistics</title>
</head>
<body>
    <p>Count: 3</p>
    <p>Sum: 9.0</p>
    <p>Average: 3.0</p> 
</body>
</html>

Variable Markers

Variable markers inject a value from the data dictionary into the output. For example:

<p>Count: {{count}}</p>
<p>Sum: {{sum}}</p>
<p>Average: {{average}}</p> 

Nested values can be referred to using dot-separated path notation; e.g. "name.first". Missing (i.e. null) values are replaced with the empty string in the generated output.

Non-map values are automatically wrapped in a map instance and assigned a default name of ".". This name can be used to refer to the value in a template. For example, the following variable marker simply echoes a value:

The value is {{.}}.

Resource References

Variable names beginning with "@" represent "resource references". Resources allow static template content to be localized.

For example, the descriptive text from the statistics template might be extracted into a properties file as follows:

title=Statistics
count=Count
sum=Sum
average=Average

The template could be updated to refer to the localized values as shown below:

<html>
<head>
    <title>{{@title}}</title>
</head>
<body>
    <p>{{@count}}: {{count}}</p>
    <p>{{@sum}}: {{sum}}</p>
    <p>{{@average}}: {{average}}</p> 
</body>
</html>

When the template is processed, the resource references will be replaced with the corresponding values from the resource bundle.

Context References

Variable names beginning with "$" represent "context references". Context values can be used to provide additional information to a template that is not included in the data dictionary.

For example, if the template context contains a value named "currentDate", the following template could be used to inject the date into the output:

<p>{{$currentDate}}</p>

Modifiers

The CTemplate specification defines a syntax for applying an optional set of "modifiers" to a variable. Modifiers are used to transform a variable's representation before it is written to the output stream; for example, to apply an escape sequence.

Modifiers are specified as shown below. They are invoked in order from left to right. An optional argument value may be included to provide additional information to the modifier:

{{variable:modifier1:modifier2:modifier3=argument:...}}

JTemplate provides the following set of standard modifiers:

  • format - applies a format string
  • ^html, ^xml - applies markup encoding to a value
  • ^json - applies JSON encoding to a value
  • ^csv - applies CSV encoding to a value
  • ^url - applies URL encoding to a value

For example, the following marker applies a format string to a value and then URL-encodes the result:

{{value:format=0x%04x:^url}}

Applications may also define their own custom modifiers. This is discussed in more detail later.

Locale-Specific Formatting

In addition to printf()-style formatting, the format modifier also supports the following arguments for locale-specific formatting of numbers and dates:

  • currency - applies currency format
  • percent - applies percentage format
  • shortDate - applies short date format
  • mediumDate - applies a medium date format
  • longDate - applies a long date format
  • fullDate - applies a full date format
  • shortTime - applies a short time format
  • mediumTime - applies a medium time format
  • longTime - applies a long time format
  • fullTime - applies a full time format
  • shortDateTime - applies a short date/time format
  • mediumDateTime - applies a medium date/time format
  • longDateTime - applies a long date/time format
  • fullDateTime - applies a full date/time format

For example, this marker transforms a date value into a localized medium-length date string:

{{date:format=mediumDate}}

Date values may be represented by one of the following:

  • an instance of java.util.Date
  • a long value representing epoch time in milliseconds
  • an instance of java.util.time.LocalDate
  • a string of the format yyy-mm-dd

Time values may be represented by one of the following:

  • an instance of java.util.Date
  • a long value representing epoch time in milliseconds
  • an instance of java.util.time.LocalTime
  • a string of the format hh:mm[:ss]

Date/time values may be represented by one of the following:

  • an instance of java.util.Date
  • a long value representing epoch time
  • an instance of java.util.time.LocalDateTime
  • a string of the format yyy-mm-ddThh:mm[:ss]

Section Markers

Section markers define a repeating section of content. The marker name must refer to an iterable value in the data dictionary (for example, an instance of java.util.List). Content between the markers is repeated once for each element in the list. The elements provide the data dictionaries for each successive iteration through the section. If the iterable value is missing (i.e. null) or empty, the section's content is excluded from the output.

For example, a data dictionary that contains information about homes for sale might look like this:

{
  "properties": [
    {
      "streetAddress": "17 Cardinal St.",
      "listPrice": 849000,
      "numberOfBedrooms": 4,
      "numberOfBathrooms": 3
    },
    {
      "streetAddress": "72 Wedgemere Ave.",
      "listPrice": 1650000,
      "numberOfBedrooms": 5,
      "numberOfBathrooms": 3
    },
    ...        
  ]
}

A template to present these results in an HTML table is shown below. The format modifier is used to present the list price as a localized currency value:

<html>
<head>
    <title>Property Listing Example</title>
</head>
<body>
<table>
<tr>
    <td>Street Address</td> 
    <td>List Price</td> 
    <td># Bedrooms</td> 
    <td># Bathrooms</em></td> 
</tr>
{{#properties}}<tr>
    <td>{{streetAddress:^html}}</td> 
    <td>{{listPrice:format=currency:^html}}</td> 
    <td>{{numberOfBedrooms}}</td> 
    <td>{{numberOfBathrooms}}</td>
</tr>{{/properties}}
</table>
</body>
</html>

Dot notation can also be used with section markers. For example:

{{#.}}
    ...
{{/}}

Separators

Section markers may specify an optional separator string that will be automatically injected between the section's elements. The separator text is enclosed in square brackets immediately following the section name.

For example, the elements of the "addresses" section specified below will be separated by a comma in the generated output:

{{#addresses[,]}}
...
{{/addresses}}

Includes

Include markers import content defined by another template. They can be used to create reusable content modules; for example, document headers and footers.

For example, the following template, hello.txt, includes another document named world.txt:

Hello, {{>world.txt}}!

When hello.txt is processed, the include marker will be replaced with the contents of world.txt. For example, if world.txt contains the text "World", the result of processing hello.txt would be the following:

Hello, World!

Includes inherit their context from the parent document, so they can refer to elements in the parent's data dictionary. This allows includes to be parameterized. Self-referencing includes can also be used to facilitate recursion.

Comments

Comment markers provide informational text about a template's content. They are not included in the final output. For example, when the following template is processed, only the content between the <p> tags will be included:

{{! Some placeholder text }}
<p>Lorem ipsum dolor sit amet.</p>

JTemplate Classes

JTemplate provides the following classes for processing template documents:

  • TemplateEncoder - template processing engine
  • Modifier - interface representing a modifier

These classes are discussed in more detail below.

TemplateEncoder

The TemplateEncoder class is responsible for merging a template document with a data dictionary. It provides the following constructors:

public TemplateEncoder(URL url) { ... }
public TemplateEncoder(URL url, Charset charset) { ... }

The first argument specifies the URL of the template document (generally as a resource on the application's classpath). The second argument represents the character encoding used by the template document. The default value is UTF-8.

The following methods can be used to get and set the optional base name of the resource bundle that will be used to resolve resource references. If unspecified, any resource references will resolve to null:

public String getBaseName() { ... }
public void setBaseName(String baseName) { ... }

Values can be added to the template context using the following method, which returns a map representing the context entries:

public Map<String, Object> getContext() { ... }

Templates are applied using one of the following methods:

public void writeValue(Object value, OutputStream outputStream) { ... }
public void writeValue(Object value, OutputStream outputStream, Locale locale) { ... }
public void writeValue(Object value, Writer writer) { ... }
public void writeValue(Object value, Writer writer, Locale locale) { ... }

The first argument represents the value to write (i.e. the data dictionary), and the second the output destination. The optional third argument represents the locale for which the template will be applied. If unspecified, the default locale is used.

For example, the following code snippet applies a template named map.txt to the contents of a data dictionary whose values are specified by a hash map:

HashMap<String, Object> map = new HashMap<>();
    
map.put("a", "hello");
map.put("b", 123");
map.put("c", true);

TemplateEncoder encoder = new TemplateEncoder(getClass().getResource("map.txt"), "text/plain");

String result;
try (StringWriter writer = new StringWriter()) {
    encoder.writeValue(map, writer);
    
    result = writer.toString();
}
    
System.out.println(result);

If map.txt is defined as follows:

a = {{a}}, b = {{b}}, c = {{c}}

this code would produce the following output:

a = hello, b = 123, c = true

Modifier

Modifiers are created by implementing the Modifier interface, which defines the following method:

public Object apply(Object value, String argument, Locale locale);

The first argument to this method represents the value to be modified, and the second is the optional argument value following the = character in the modifier string. If an argument is not specified, this value will be null. The third argument contains the template's locale.

For example, the following class implements a modifier that converts values to uppercase:

public class UppercaseModifier implements Modifier {
    @Override
    public Object apply(Object value, String argument, Locale locale) {
        return value.toString().toUpperCase(locale);
    }
}

Custom modifiers are registered by adding them to the modifier map returned by TemplateEncoder#getModifiers(). The map key represents the name that is used to apply a modifier in a template document. For example:

TemplateEncoder.getModifiers().put("uppercase", new UppercaseModifier());

Note that modifiers must be thread-safe, since they are shared and may be invoked concurrently by multiple encoder instances.

Additional Information

This guide introduced the JTemplate framework and provided an overview of its key features. For additional information, see the the examples.