Runtime dispatching freemarker macros for pojo views

One of the (many) reasons I switched from JSP to FreeMarker is that I couldn’t achieve what I describe in this post. Tutorials or blog posts regarding this situation were never to be found, and in addition it was really hard to find anyone considering this issue a real problem.

The problem

Suppose we are building an issue tracking system. We have a rich Domain Model which includes entities such as User, Project, Account, Role etc. We’ve also got an abstract Issue object which is the root of the issue’s hierarchy. Concrete classes extending Issue include Bug, Feature, Request and Change. These 4 POJOs inherit common fields from Issue but add fields, methods and logic of their own.

Each of the issue’s subclass will need to have a slightly different HTML view. I tend to use the composite design pattern for my views, so I can break the HTML down to small reusable components. So it is obvious that we’re going to need 4 different views, one for each of them. Here are those issue rendering methods (presented in an imaginary pseudolanguage which combines EL, HTML and functions):

renderBug(bug) {
  <fieldset>
    <legend>Bug #${bug.id}</legend>
    <p>Author: ${bug.author}</p>
    <p>Date: ${bug.date}</p>
    <p>Description: ${bug.description}</p>
    <p>Steps to recreate bug: ${bug.stepsToRecreate}</p>
  </fieldset>
}

renderFeature(feature) {
  <fieldset>
    <legend>feature #${feature.id}</legend>
    <p>Author: ${feature.author}</p>
    <p>Date: ${feature.date}</p>
    <p>Description: ${feature.description}</p>
    <p>Related URL: ${feature.url}</p>
    <p>Screenshot upload: <img src="${feature.screenshot}" /></p>
  </fieldset>
}

...

Our DAO (probably called IssueDao) is going to fetch a Collection<Issue> (a bunch of issues) from the database for a particular use case. The runtime type of each of those entities cannot be Issue but it will be Bug, Feature, Request or Change. The problem is that we are presenting them altogether in the same screen, so in order to render them we have to write code such as this:

foreach(issues as issue) {
  if (issue instanceof Bug) renderBug(issue); continue;
  if (issue instanceof Feature) renderFeature(issue); continue;
  if (issue instanceof Request) renderRequest(issue); continue;
  if (issue instanceof Change) renderChange(issue);
}

If this doesn’t seem very bad to you, here is an actual view implementation of a slightly bigger hierarchy using JSP 2.0 Tag Files:

if (t instanceof ActivityInternal) {%><p:activityInternalView pojo="${t}" /><%;}
if (t instanceof ActivityExternal) {%><p:activityExternalView pojo="${t}" /><%;}
if (t instanceof ActivityMilestone) {%><p:activityMilestoneView pojo="${t}" /><%;}
if (t instanceof Review) {%><p:reviewView pojo="${t}" /><%;}
if (t instanceof PublicationReport) {%><p:publicationReportView pojo="${t}" /><%;}
if (t instanceof PublicationWebsite) {%><p:publicationWebsiteView pojo="${t}" /><%;}
if (t instanceof InfoConference) {%><p:infoConferenceView pojo="${t}" /><%;}
if (t instanceof InfoBase) {%><p:infoBaseView pojo="${t}" /><%;} 
if (t instanceof InfoChannel) {%><p:infoChannelView pojo="${t}" /><%;}
if (t instanceof Meeting) {%><p:meetingView pojo="${t}" /><%;}
if (t instanceof Interpretation) {%><p:interpretationView pojo="${t}" /><%;}
if (t instanceof BudgetItem) {%><p:budgetItemView pojo="${t}" /><%;}
if (t instanceof FocusGeneral) {%><p:focusGeneralView pojo="${t}" /><%;}
if (t instanceof FocusResearch) {%><p:focusResearchView pojo="${t}" /><%;}
if (t instanceof Risk) {%><p:riskView pojo="${t}" /><%;}
if (t instanceof QAChecklist) {%><p:QAChecklistView pojo="${t}" /><%;}
if (t instanceof TargetAudience) {%><p:targetAudienceView pojo="${t}" /><%;}
if (t instanceof LessonsLearned) {%><p:lessonsLearnedView pojo="${t}" /><%;}

If you still don’t think this is bad, you can stop reading ;)

What not to do

In a project I did in my early JSP days, what I did was to put all the view logic in the Java class! So it looked like this (this is actual Java):

public class Bug extends Issue {

  ...

  public String renderMe() {
    return "<fieldset><legend>" + this.getName() + "</legend>" + 
           "<p>Author: " + this.getAuthor() + "</p>" +
           "<p>Date: " + this.getDate() + "</p>" +
           "<p>Description: " + this.getDescription() + "</p>" +
           "</fieldset>";
  }
}

Although this type of code is a perfect candidate for The Daily WTF, the (only) advantage was that I could now render my pojos using (pseudocode):

foreach(issues as issue) {
  issue.renderMe();
}

The solution

It seems that all we want is the ability to construct and dynamically (reflectively in Java terms) call the appropriate render tag each time. In freemarker we define macros which look like this:

<#macro renderBug bug>
  <fieldset>
    <legend>Bug #${bug.id}</legend>
    <p>Author: ${bug.author}</p>
    <p>Date: ${bug.date}</p>
    <p>Description: ${bug.description}</p>
    <p>Steps to recreate bug: ${bug.stepsToRecreate}</p>
  </fieldset>
</#macro>

We need a way to call renderXXX where XXX is the short class name of the issue in question. And here is how you can do this in freemarker:

<#local macroname='render' + issue.class.name?split(".")?last />
<@.vars[macroname] issue />

For an issue of runtime type com.example.Foo, it concatenates the word “render” with “Foo” and calls the macro with that name. The magic happens with the help of the .vars special variable. It allows us to access variables by name. The full code now becomes:

<#macro renderIssue issue>
  <#local macroname='render' + issue.class.name?split(".")?last />
  <@.vars[macroname] issue />
</#macro>

<#list issues as issue>
  <@renderIssue issue />
</#list>

By the way, this capability is usually present in dynamic scripting languages. So for example there are many ways to do that in PHP.

using dynamic evaluation
$functionName = "renderBug";
$functionName($issue);
using eval
eval("renderBug($issue);");
using call_user_func (probably safest of all)
call_user_func("renderBug", $issue);

14 Responses to “Runtime dispatching freemarker macros for pojo views”

  1. Victor Says:

    Good article – it shows how flexible you can write Freemarker templates.

    There is however a small bug:

    –> <–

    … should be

  2. Victor Says:

    Now I noticed how badly HTML-tags worked in this comment field.

    What I meant to say was:

    (open-tag)#renderIssue issue /(closetag) should be

    (open-tag)@renderIssue issue /(closetag).

  3. cherouvim Says:

    Thanks Victor! Fixed.

  4. Bill Bartmann Says:

    Cool site, love the info.

  5. biddster Says:

    Could you not do issue.class.simpleName and avoid the splitting?

  6. cherouvim Says:

    @biddster: Yes of course. I wrote this when I was still on JDK 1.4

  7. biddster Says:

    Good point. Thanks for the article, exactly what I needed. I’m creating UI widget system using freemarker and this was just what I needed.

  8. cherouvim Says:

    @biddster: glad it helps.

  9. kevin Says:

    I find your post intriguing and I’m trying to do something similar… I want to invoke a particular getter based on the value that is in another value, so that I can use the same template to render multiple different types of pojos. So I have a pojo of type Person and a sequence of attribute names like “firstName”, “lastName”, etc. both of which were passed in at runtime. Then I want my template to invoke pojo.firstName, pojo.lastName, etc to populate a table. This same template would be able to fill the table with data from any kind of pojo, as long as you also passed in the corresponding sequence of attribute names you wished to pull from the pojo. Do you happen to know if this is possible in Freemarker?

  10. cherouvim Says:

    @kevin: yes it’s possible. In fact I’m doing it all the time in a form handling framework I’ve written.

    < #local fieldName="firstName" />
    ${(“person.” + fieldName)?eval}

    The above evaluates the expression ${person.firstName} which is what you want.

  11. kevin Says:

    You are a savior!

  12. Anon Says:

    This is a typical (and meaningless) argument “strong-typed language vs weak-typed language”. Why bother with Java if you are not planning to take advantage of it?

  13. cherouvim Says:

    @Anon: I’m not sure if you understood this post.

    I use Java to full potential but default web templating option (JSP) suffers. I present alternatives and compare with other languages.

  14. D Kevin Says:

    I found your article pretty handy. I am trying to relate it to my requirement.
    I need to write a freemarker macro which would take a “java bean object” as argument.
    This macro should pass this “bean object” to java class reflection class, get all the bean properties and render it to html page.

    After going through your post, I feel it’s definitely doable by doing some brainstorming.
    Any help / comments would be appreciated !!!