Freemarker Error Handling

2015/10/25

The possible exception

The exception that can occur regarding Freemarker could be classified like this:

  • Exceptions occurring when you configure Freemarker: Typically you configure Freemarker only once in your application, when your application initializes itself.
  • Exceptions occurring when loading and parsing templates: When you call Configuration.getTemplate(...), Freemarker has to load the template file into the memory and parse it. During this, two kinds of exceptions can occur:

    • IOException because the template file was not found, or other I/O problem occurred while trying to read it (you have no right to read the file, or there are disk errors).
    • freemarker.core.ParseException because the template file is syntactically incorrrect according the rules of the FTL language. This exception is an IOException subclass.
  • Exception occurring when executing templates. Two kinds of exceptions can occur:

    • IOException because there was an error when trying to write into the output writer.
    • freemarker.template.TemplatException because other problem occurred while executing the template. For example, a frequent error is when a template refers to a variable which is not existing. Be default, when a TemplatException occurs, Freemarker prints the FTL error message and the statck trace to the output writer with plain text format, and then aborts the template execution by re-throwing the TemplatException, which then you can catch as Template.process(...) throws it.

      class MyTemplateExceptionHandler implements TemplateExceptionHandler {
          public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out)
                  throws TemplateException {
              try {
                  out.write("[ERROR: " + te.getMessage() + "]");
              } catch (IOException e) {
                  throw new TemplateException("Failed to print error message. Cause: " + e, env);
              }
          }
      }
      
      ...
      
      cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());
      

Handling missing values

${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}

The output will be:

No mouse.
Jerry

product.color!"red"

This will handle if color is missing inside product, but will not handle if product is missing. That is, the product variable itself must exist, otherwise the template processing will die with error.

(product.color)!"red"

This will handle if product.color is missing. That is, if product is missing, or product exists but it does not contain color, the result will be red, and no error will occur.

The important difference between this and the previous example is that when surrounded with parentheses, it is allowed for any component of the expression to be undefined, while without parentheses only the last component of the expression is allowed to be undefined.

Missing value test operator
<#if mouse??>
Mouse found
</#if>