Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JTemplate: Template-Driven REST Services for Java

DZone's Guide to

JTemplate: Template-Driven REST Services for Java

For developers, writing REST services in Java is often a lot of boilerplate work and painful separation of content from coding. Here's an alternative.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

JTemplate is an open-source implementation of the CTemplate templating system (aka "Mustache") for Java. It also provides a set of classes for implementing template-driven REST services in Java.

This article introduces the JTemplate framework and provides an overview of its key features.

Templates

Templates are documents that describe an output format such as HTML, XML, 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. In JTemplate, 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>

JTemplate provides the TemplateEncoder class for merging a template document with a data dictionary. Templates are applied using one of the following TemplateEncoder 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 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}}

... then this code would produce the following output:

a = hello, b = 123, c = true

REST Services

In addition to template processing, JTemplate provides several classes for use in implementing template-driven REST services:

  • DispatcherServlet: abstract base class for REST services.
  • RequestMethod: annotation that associates an HTTP verb with a service method.
  • ResourcePath: annotation that associates a resource path with a service method.
  • ResponseMapping: annotation that associates a template with a method result.
  • JSONEncoder: class used for encoding responses that are not associated with a template.

DispatcherServlet is an abstract base class for REST services. Service operations are defined by adding public methods to a concrete service implementation.

Methods are invoked by submitting an HTTP request for a path associated with a servlet instance. Arguments are provided either via the query string or in the request body, like an HTML form. DispatcherServlet converts the request parameters to the expected argument types, invokes the method, and writes the return value to the response stream.

The RequestMethod  annotation is used to associate a service method with an HTTP verb such as GET or  POST. The optional ResourcePath annotation can be used to associate the method with a specific path relative to the servlet. If unspecified, the method is associated with the servlet itself.

The optional ResponseMapping annotation associates a template document with a method result. If specified, TemplateEncoder is used to apply the template to the return value to produce the final response. Otherwise, the return value is automatically serialized as JSON using the JSONEncoder class.

For example, the following class might be used to implement a service that performs the simple statistical calculations discussed in the previous section. The static mapOf() and entry() methods are provided by DispatcherServlet to help simplify map creation: 

@WebServlet(urlPatterns={"/math/*"}, loadOnStartup=1)
public class MathServlet extends DispatcherServlet {
    private static final long serialVersionUID = 0;

    @RequestMethod("GET")
    @ResourcePath("/statistics")
    @ResponseMapping(name="statistics~html.txt", mimeType="text/html")
    public Map<String, ?> getStatistics(List<Double> values) {
        int count = values.size();

        double sum = 0;

        for (int i = 0; i < count; i++) {
            sum += values.get(i);
        }

        double average = sum / count;

        return mapOf(
            entry("count", count),
            entry("sum", sum),
            entry("average", average)
        );
    }
}

A specific representation is requested by appending a tilde ("~") character to the service URL, followed by a file extension representing the desired document type. The MIME type associated with the extension is used to identify the template to apply.

For example, a GET for the following URL would return the default JSON response:

/math/statistics?values=1&values=3&values=5

However, a GET for this URL would return an HTML document produced by applying the template defined in statistics~html.txt to the result:

/math/statistics/~html?values=1&values=3&values=5

Additional Information

This article introduced the JTemplate framework and provided an overview of its key features.The latest JTemplate release can be downloaded here. For more information, see the project README.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
json ,rest ,java ,jtemplate

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}