FreeMarker: An open alternative to JSP

How the template-based, open source API FreeMarker trumps JSP

JavaServer Pages (JSP) is intended to be the glue that binds EJB and HTML code. Placed in the key boundary between data and presentation, JSP endeavors to be both intuitive enough for non-Java programmers and powerful enough for Java programmers to accomplish complex enterprise-level tasks on the server. The advent of JSP 1.1 and custom tag libraries is a welcome amendment to the original JSP design, yet JSP still falls short of its original purpose of separating presentation from data.

The faults of JSP

So what's wrong with JSP? It depends on the scope of the project. You cannot argue that one of JSP's strengths lies in integrating an existing codebase with an HTML-based presentation layer that is in need of a few dynamic elements. This integration often involves a Java developer hacking some JSP code into a previously authored HTML page.

In larger projects, time constraints often dictate that the HTML and Java be developed in parallel. Here's where JSP begins to show its faults. First, JSP relies too heavily on Java syntax. HTML coders seldom know Java syntax well enough to author JSP pages entirely by themselves. A typical solution is to have the Java developers "rope off" sections of HTML code with comments, to which they will later add JSP code. This approach leaves the door wide open for a complex form of feature-creep known as "Why doesn't it work the way it did when I originally wrote it?" Let's face it, HTML authors want their code touched about as much as Java programmers do, which is to say not at all. Additionally, it can be difficult to test the validity of the HTML depending upon how much the JSP dynamically generates it. This could leave the HTML authors sitting around waiting for the JSP to be inserted before they can even test their work.

You should also be pessimistic about JSP's long-range prospects. If you've ever tried to parse a typical JSP page with an XML parser, you know that there are elements of JSP (and not incidentally, also of HTML) that are not XML-compliant; for example, the <%...%> directive. This implies, of course, that current JSP tags are bound to HTML source files. This might not appear to be an obstacle now, and it won't be for a while. But some day in the future runtime optimizations will lead to XML output from the server and XSLT transformations on the client browser, and when that day comes all those JSP pages will be relegated to the seldom-touched recesses of their respective companies' source control systems. Additionally, to date, JSP hasn't been released under an open source license. Although it is unlikely that Sun will retract support for this technology, companies should be aware that they are building an extremely visible component of their business upon a technology whose modifications they have no control over.

For many, the most compelling argument against JSP is its halfhearted attempt at realizing the model-view-controller (MVC) design pattern. This pattern defines an architectural three-way split for an application, separating data elements (the model) from the data presentation (the view) from the manipulation of the data into the presentation (the controller). JSP makes a valiant attempt to live in harmony with this design pattern, but MVC proponents feel that requiring Java code (the controller) in the HTML (the view) is a violation of their beloved pattern. And they're right. JSP 1.1's custom tags eradicate some of this inconsistency, letting you build a library of tags that encapsulate logic and/or data and provide a JSP interface to them. The drawback is that custom tags are tiresome to configure and require a relative mountain of code to develop something you cannot use outside of JSP. Additionally, instead of relying on the Java language's strengths in inheritance, JSP custom tags rely on the Reflection API, which is a relatively inefficient technology. I say inefficient because instead of calling a method directly, Reflection lets you call a Reflection API method that will attempt to construct a reference to the desired method or class. This additional step comprises much of the inefficiency because of the time it takes to dynamically create the reference to the desired method or class.

To highlight some of JSP's shortcomings, an MVC litmus test might be useful. Here's the scenario: you'd like to display all the orders a particular customer has made over a certain period of time. This display should have the flexibility of being in an HTML table or in an HTML ordered list. According to strict MVC interpretation, this shouldn't be a difficult task; if presentation is truly independent of data, changing one should have no effect on the other. Unfortunately, in JSP you have two choices, neither of which is attractive. (Take note of where and how the table structure gets filled.)

  1. Using a JSP 1.0-like mechanism, you have a Vector (or other java.util.List-like object) containing order objects. This Vector is available to the JSP as a JavaBean:

    <table>
       <% 
          orderVector = customer.getOrders();
          for( int i=0; i<orderVector.size(); i++){
             Order o = orderVector.elementAt(i);
       %>
       <tr>
          <td><%= o.getDate() %></td>
          <td><%= o.getOrderID() %></td>
       </tr>
       <% } %>
    </table>
    
  2. Using a JSP 1.1-specific mechanism, you have a custom tag similar to <javaworld:orderlist/>. After configuring the tag library file and remembering to import the correct tag library at the top of the JSP file, you can start writing the Java code that looks like the following:

    ...
    BodyContent body = this.getBodyContent();
    JspWriter writer = body.getEnclosingWriter();
    writer.print("<table>");
          orderVector = customer.getOrders();
          for( int i=0; i<orderVector.size(); i++){
             Order o = orderVector.elementAt(i);
             writer.print("<tr>");
             writer.print("<td>" + o.getDate() + "</td>" );
             writer.print("<td>" + o.getOrderID() + "</td>" );
             writer.print("</tr>");
          }
          writer.print("</table>");
          ...
    

You can immediately see that neither of these two options is acceptable; each violates the MVC pattern. The first requires elements of the model in the view. Should the structure of the Order or Customer object change (which is, mind you, part of the model), changes would need to be made to the Java elements present in the view. That is not good, but it could be worse. In the ideal MVC environment, changes to one element should never affect another.

The second option requires elements of the view in the model. Should you need to change the HTML table (the view) to an unordered list, the custom tag would require modifications. That is even worse than the first option. In addition to violating good MVC practice, the second option forces a recompilation of the code, which implies regression testing, stopping the servers, a new or updated installation, and all the other little evils that ride on the coattails of changing deployed code. There has to be a better way.

FreeMarker to the rescue

In a perfect world, you'd expect your magic bullet to be an open source technology that's compatible with Java but not reliant on it, a strict MVC adherent, and independent of any source file type. Allow me to introduce FreeMarker, an open source project that meets all of the above standards. FreeMarker consists of a class library that provides template processing capabilities and an API that lets you extend or modify FreeMarker's behavior. Like JSP 1.1, FreeMarker's template processing engine replaces tags in the source file with dynamically generated data. Unlike JSP, FreeMarker tags are independent of the source-file format; they can just as easily be placed in an XML file, WML file, HTML file, or plain text file. FreeMarker is actually independent of servlets altogether, making it just as useful on the client as on the server. And unlike the JSP 1.1 XML-configured architecture, FreeMarker provides a lightweight framework that you can easily extend to build a powerful application without relying on runtime-inefficient technologies like Java Reflection to do the legwork. A unique feature of FreeMarker is its support for an embedded template scripting language. As you will see later in the article, this feature helps encapsulate commonly used presentation logic for use across pages.

The central concepts of FreeMarker are the template and the ModelRoot. In the FreeMarker world, a template is any text file that contains FreeMarker tags. These tags control the behavior of the FreeMarker template processor -- more on that later. The ModelRoot, as its name implies, is the root of the data model. The term "root" conjures images of a recursive treelike structure, and this is exactly what the FreeMarker's data model resembles. On a grand scale, objects conforming to the FreeMarker API are placed into the ModelRoot where they are extracted by the controller and placed into the view.

FreeMarker distinguishes among four categories of objects. The TemplateScalarModel, TemplateHashModel, TemplateListModel, and TemplateMethodModel interfaces describe what each of those objects should look like. FreeMarker kindly provides default implementations of all but the last of those interfaces, respectively known as SimpleScalar (scalars), SimpleHash (hashes), and SimpleList (lists). Each of these types should be familiar to you, as they resemble objects provided in the standard JDK distribution. This eases the learning curve for developers trained on these Java concepts. Scalars represent single-valued objects, such as a String or a boolean. Hashes are similar to the Hashtable object, an associative array of values retrieved by a unique key. Lists are similar to java.util.List objects, supporting read-only methods like next and hasNext methods, as well as other methods like rewind. (The SimpleList class contains additional methods to add objects to the list, but the interface doesn't require that). Finally, implementations of the TemplateMethodModel interface provide a mechanism for the presentation layer to call a method on the model layer, passing on the arguments it may need to complete the request. This is similar to JSP 1.1's custom tags except that it requires no special configuration. As you will see later, it is useful for, among other things, highly dynamic data extraction.

The elements of FreeMarker are orthogonal, letting you create complex data models that accurately represent the underlying object model. For instance, TemplateHashModel objects can contain any of the other object types, including instances of TemplateHashModel. The same goes for lists. Scalars are always the leaves of the ModelRoot tree as they cannot contain any other object type. The API requires that the object serving as the ModelRoot is an instance of an interface known as TemplateModelRoot, which SimpleHash conveniently implements. A hypothetical ModelRoot tree could have the structure shown in Figure 1:

Figure 1. The ModelRoot can contain any number of nested lists, hashes, and methods. Scalars are always the leaves of the tree.

The ModelRoot contains a TemplateListModel object, which in turn contains three TemplateHashModel objects. Each of those hashes contain key-value pairs, where the key is a java.lang.String object and the value is any object that implements the TemplateModel interface. This is the root interface that all FreeMarker objects must implement. In that case, the hashes contain TemplateScalarModel objects, which implement TemplateModel.

The face of FreeMarker

The MVC design pattern forces you to think of the view as an inherently different animal than the model and the controller. FreeMarker encourages that by providing a unique look to the presentation layer. At this layer, the syntax of FreeMarker tags is more reminiscent of a typical shell-scripting language than of Java code fragments. That proves to dramatically improve the learning curve for Webmasters and HTML authors. Tags in the source file call out attribute values in a familiar dot notation format. For instance, even without understanding the details of how FreeMarker works, it should be evident that ${user.preference.page_color} references the page_color attribute of the preference structure, which is contained in the user structure.

Conceptually, it is easiest to understand the job of the controller (FreeMarker's template processor) as being responsible for replacing the tags in the template with their corresponding elements from the ModelRoot. To illustrate, assume that you build a compound data model by adding objects to the ModelRoot as below. That code duplicates the JSP code from the beginning of the article with a noticeable FreeMarker flavor.

1 2 3 Page
Recommended
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more