Topstone Software Consulting

Java Template Engines

Introduction

All web applications display dynamic information that is fetched from the computer resources that support the web application (in contrast to web sites, which may only display static content). In many cases a web application is supported by a web server like Tomcat or by "serverless" components like Amazon Web Services (AWS) Lambda. To simplify the discussion in this article, the back end system will be referred to as a web server.

When the web application page is displayed, it will contain the dynamic information fetched from the web server. There are two ways that dynamic information from the server can be included in the web page:

  1. JavaScript running on the client (the web browser) can fetch the data from the server and insert the data into the page by modifying the in-memory representation (e.g., the DOM) of the page HTML.
  2. The HTML for the web page can modified on the sever with the data inserted into the HTML for the page. This is often referred to as "server side rendering".

This article discusses three template engines that can be used for server side rendering for a Java application that leverages the Spring framework.

Displaying Server Side Data

The image below shows part of a screen capture for the AWS Cognito demonstration application. This simple page is displayed after the user logs into the application. The page displays the user name (bear) and some simple profile information for the user.

The data is included in the web page using template engine markup in the HTML. In the example below, FreeMarker markup is used.

The HTML for this section of the web page is shown below:

    <#if user_info?? && (user_info?length > 0)> <!--  user_info != null -->
	<div class="row">
	   <div class="col-md-12">
	       <h2 align="center">Hi ${user_info.getUserName()}, you are now logged into your application</h2>
	   </div>
	</div> <!-- row -->
	<div class="row">
	    <div class="col-md-2"></div>
		<div class="col-md-10">
	           <h4>Profile information</h4>
	          <div>Email: ${user_info.getEmailAddr() }</div>
	          <div>Location: ${user_info.getLocation() }</div>
	    </div>
	</div>
    </#if>
     

In the Spring Model-View-Controller paradigm, each web page has an associated controller class that contains functions that handle the web page interactions (e.g., HTTP GET and POST, if there is a form). The Java function for the application page is shown below.

 protected final static String USER_SESSION_ATTR = "user_info";

    @GetMapping("/application")
    public ModelAndView application(ModelMap model, RedirectAttributes redirect, HttpServletRequest request ) {
        String nextPage = "application";
        UserInfo info = (UserInfo)request.getSession().getAttribute(USER_SESSION_ATTR);
        if (info != null) {
            model.addAttribute("user_info", info);
        } else {
            // The user is not logged in, so go to the login page
            nextPage = "index";
        }
        return new ModelAndView(nextPage, model);
    }

In the above example, a UserInfo object is added to the Model map with user_info as the key value. When the web page is rendered on the server by the template engine (in this case FreeMarker), the values from the object are filled in where it is referenced in the page HTML.

The HTML web page is referred to as a template since data values dynamically replace the template markup when the page is rendered.

Java Template Engines

One of the first template engines was PHP, which dates to the early days of the Web.

In 1999 Sun Microsystems released Java Server Pages (JSP), which is a template engine for Java web applications. In 2006 the Java Server Pages Tag Library (JSTL) was released. The JSTL makes JSP easier to use and the resulting web pages are easier to understand.

In addition to JSP/JSTL, there have been a number of template engines released for the Java software ecosystem. These include Apache Velocity, FreeMarker, Thymeleaf and Pippo (which seems to have evolved from an earlier template engine named Pebble). Groovy Server Pages (GSP) are used for Grails/Groovy applications.

Choosing a Template Engine

A web application may consist of a large number of web pages. For example, the nderground social network, built by Topstone Software, has over 35 web pages. Designing and developing these web pages represents a significant portion of the effort that went into building the web application. Choosing the template engine for web page implementation is a important investment in the software architecture.

A core requirement in evaluating a Java template engine was whether it is supported by the Spring framework, which Topstone Software uses to develop web applications. Three template engines, which are supported by Spring, have been evaluated.

  1. Java Server Pages with the Java Server Pages Tag Library (JSP/JSTL)
  2. Thymeleaf
  3. FreeMarker

In addition to supporting Spring, the template library needs to support the ability to include (insert) HTML fragements into the main page. This feature allows common CSS and JavaScript includes in the page header and common page headings and footers to be included in the application pages.

The best way to evaluate a template engine (or any software development framework) is to use it in a real application. Each of the template engines was used in a version of the Cognito Demonstration application.

JSP and JSTL

The Cognito demonstration application was developed to explore the AWS Cognito authentication service. The application includes ten web pages, where almost every page includes dynamic server side data.

The original version of the Cognito demonstration application uses JSP and JSTL templates in the web pages.

JSTL supports the <c:import ... > tag which allows HTML fragements to be included in the page or page header.

The example below shows how conditional logic can be added for server side page generation. When a page is sent to the client (the web browser), it will consists of static HTML, which has been dynamically generated on the server.

               <c:choose>
		  <c:when test='${change_type != null && change_type.equals("change_password")}'>
		       <input class="invisible" type="text" id="user_name" name="user_name" value="${user_name_val}">
		  </c:when>
		  <c:otherwise>
			<div class="form-group row">
				<label for="title" class="col-sm-4 col-form-label">User name:</label>
				<!--  if the user name is OK, fill it in so the user doesn't have to keep retyping it if, for
				      example, the password and the duplicate password don't match. -->
				<div class="col-sm-8">
				<c:choose>
				   <c:when test="${user_name_val != null && user_name_val.length() > 0}">
				   	    <input type="text" id="user_name" name="user_name" value="${user_name_val}">
				   </c:when>
				   <c:otherwise>
					     <input type="text" id="user_name" name="user_name" placeholder="User name">
				   </c:otherwise>
				</c:choose>
				</div> <!-- col-md-8 -->
			</div> <!--  form-group row -->
		</c:otherwise>
		</c:choose>

Thymeleaf

Thymeleaf is currently popular in the Spring community. Many articles on Spring use Thymeleaf in the example web pages. One of the best references on the Spring framework, Spring in Action, Fifth Edition, by Craig Walls, Manning Press, October 2018, also uses Thymeleaf.

Thymeleaf has a number of issues, some of which are stylistic.

Thymeleaf embeds the Thymeleaf markup in HTML tags, usually <div> or <span> tags. I don't find this as clean and easy to read and write as JSP/JSTL or FreeMarker tags. An example, showing Thymeleaf markup, is shown below.

 	    <div th:if="${change_type != null && change_type.equals('change_password')}">
	         <input class="invisible" type="text" id="user_name" name="user_name" th:value="${user_name_val}">
	    </div>
	    <div th:unless="${change_type != null && change_type.equals('change_password')}">
	        <div class="form-group row">
				<label for="title" class="col-sm-4 col-form-label">User name:</label>
				<!--  if the user name is OK, fill it in so the user doesn't have to keep retyping it if, for
				      example, the password and the duplicate password don't match. -->
				<div class="col-sm-8">
				   <div th:if="${user_name_val != null && user_name_val.length() > 0}">
				         <input type="text" id="user_name" name="user_name" th:value="${user_name_val}">
				   </div>
				   <div th:unless="${user_name_val != null && user_name_val.length() > 0}">
				         <input type="text" id="user_name" name="user_name" placeholder="User name">
				   </div>
				</div> <!-- col-md-8 -->
			</div> <!--  form-group row -->
	    </div>

Thymeleaf supports th:replace and th:include tags which allow sections of HTML to be inserted into the page. The example below shows how the th:replace tag can be used to insert the CSS and JavaScript links into the page head. The th:replace tag is also used to add a page header so that pages have common title headings.

<html  xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head_includes.html :: head_files">
</head>
<title>Cognito Demo Application Login</title>

<body>
	<div class="container">
		<div style="padding-top: 1em;"></div>
		<div th:replace="fragments/title.html :: title"></div>
		<div style="padding-top: 1em;"></div>

Thymeleaf has some issues that go beyond the stylistic.

When Thymeleaf encounters an error while processing Thymeleaf markup, it throws a Java exception. This exception does not contain any information (i.e., line and character number) about what caused the error. This can make finding and correcting a Thymeleaf markup error time consuming, slowing application development.

Another concern is that Thymeleaf could become an orphan open source project.

Although Thymeleaf is popular in the Spring community and Thymeleaf is currently supported by the Spring Tool Suite project builder, I noticed that Thymeleaf is not supported by Pivotal (the company that supports the Spring framework). Thymeleaf is supported by three GitHub committers and most of the GitHub commits are from two people. If these GitHub committers are not able or willing to support Thymeleaf, the project could become an orphan.

FreeMarker

FreeMarker is supported by an Apache Software Foundation and has a huge user community, including page templates for several content management systems (see Who Uses FreeMarker). FreeMarker also has support for the Spring framework.

On a stylistic level, I prefer FreeMarker's JSP/JSTL like tag structure. An example is shown below. Note that the expressions within the conditionals do not have to be quoted.

	    <#if change_type?? && (change_type.equals("change_password"))>
	         <input class="invisible" type="text" id="user_name" name="user_name" value=${user_name_val}>
	    <#else>
	        <div class="form-group row">
				<label for="title" class="col-sm-4 col-form-label">User name:</label>
				<!--  if the user name is OK, fill it in so the user doesn't have to keep retyping it if, for
				      example, the password and the duplicate password don't match. -->
				<div class="col-sm-8">
				   <#if user_name_val?? && (user_name_val?length > 0)>
				         <input type="text" id="user_name" name="user_name" value=${user_name_val}>
				   <#else>
				         <input type="text" id="user_name" name="user_name" placeholder="User name">
				   </#if>
				</div> <!-- col-md-8 -->
			</div> <!--  form-group row -->
	    </#if>

FreeMarker supports an include tag that can be used to include HTML sections in the page. An example is shown below.

<head>
<#include  "fragments/head_includes.html">
</head>
<title>Cognito Demo Application Login</title>

<body>
	<div class="container">
		<div style="padding-top: 1em;"></div>
		<#include "fragments/title.html">
		<div style="padding-top: 1em;"></div>

FreeMarker is not without its quirks. I spent hours of frustrating experimentation before I could get images to load on the FreeMarker pages (see the Java configuration class cognitodemo.freemarker.config.AppConfig in the FreeMarker GitHub project).

Free marker also has a syntax that can take getting used to. In the example below the FreeMarker page references the String variable login_error. However, this FreeMaker markup will result in a FreeMarker parsing error.

 <#if login_error != null && (login_error.length() > 0)> <!-- Error! -->

FreeMarker requires you to use the FreeMarker operators for comparison to null and for string length. The null comparision operator is "??" The String length() function is not allowed. Instead the built-in FreeMarker length operator must be used: login_error?length. The correct FreeMarker markup is shown below:

 <#if login_error?? && (login_error?length > 0)> <!-- correct -->

What about Velocity?

Velocity is a vintage template engine and alternative to JSP/JSTL. Velocity has a large community and many features. From 2010 to 2017 there were no major Velocity releases and some people, including the Spring development team, concluded that the Velocity project was in hibernation.

In a Jira issue posting the Spring development group states that Velocity will not be a supported part of Spring, but that the Apache Velocity group is welcome to support Spring adapters for Velocity.

In 2017 Apache Velocity released version 2.0 of the template engine and in 2018 they released version 3.0 of the Velocity tools. So the Velocity project seems to be active.

References on Velocity and integrating Velocity with Spring include:

Although it appears that Velocity can be integrated with Spring, I am concerned that Velocity compatibility with Spring doesn't seem to be a focus of either the Spring project or the Apache Velocity group. Given this concern and the fact that at some point exploration has to give way to application development, I decided not to develop a Velocity version of the Cognito demonstration application.

Conclusion

After investigating JSP/JSTL, Thymeleaf and FreeMarker, I have decided to use FreeMarker for my next Topstone Software web application.

A concern with JSP/JSTL is that not much has happened with the technology since 2008. Although there is an active open source community behind Java, it is not clear that this extends to JSP/JSTL. This makes the technology less attractive compared to FreeMarker, which has a huge user community and an active Apache project.

Thymeleaf has a small development group. Unless this group expands, I am concerned that Thymeleaf could become an orphan project. The fact that, currently, Thymeleaf does not provide useful error messages when it encounters a markup error can make finding problems time consuming. On a stylistic level, I don't like the Thymeleaf markup as much as JSP/JSTL or FreeMarker.

FreeMarker is an Apache Foundation project with a large user community. When the FreeMarker processor encounters an error, it provides useful error messages. After using Groovy Server Pages and JSP/JSTL, the FreeMarker markup feels familiar.

Cognito Demonstration Application GitHub Repositories

Appendix

Model-View-Controller vs. Client Side Page Rendering

One objection to the server side model-view-controller (MVC) model that is used in the Cognito demonstration application is that the client side web page logic is integrated with the server side controllers. Changes to the web pages may result in changes to the controller code.

An alternative approach is to implement server side code that supports an API that returns the data for client side display. The client side code, implemented with a JavaScript framework like AngularJS or React, uses API references (HTTP GET operations) to fetch the data that is displayed on the web page.

Following this architecture the client display layer is separated from the server code. The server code only has to be change if there is a requirement to display new data.

In this architecture, the application display on the client side could be completely changed without affecting the server.

For large organizations, moving away from the model-view-controller paradigm, where the controller is on the server, may be attractive. The client side and server side groups can work in parallel with less impact.

For a smaller organization or for rapid application development, developing a monolithic Spring MVC application will usually be faster and more flexible since the same developer(s) will be developing both the server side controller and the client side web pages.

After the application gains market traction, it may make sense to move toward an architecture that uses Spring on the server to implement the server API and a client side framework like AngularJS for client side display. However, adopting this approach too early is likely to increase development time when it is important to get the application in the hands of users as soon as possible.

December 2018