| <!doctype html> |
| <!-- Generated by FreeMarker/Docgen from DocBook --> |
| <html lang="en" class="page-type-section"> |
| <head prefix="og: http://ogp.me/ns#"> |
| <meta charset="utf-8"> |
| <title>Error handling - FreeMarker Manual</title> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <meta name="format-detection" content="telephone=no"> |
| <meta property="og:site_name" content="FreeMarker Manual"> |
| <meta property="og:title" content="Error handling"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="http://example.com/pgui_config_errorhandling.html"> |
| <link rel="canonical" href="http://example.com/pgui_config_errorhandling.html"> |
| <link rel="icon" href="favicon.png" type="image/png"> |
| <link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1594338519184"> |
| </head> |
| <body itemscope itemtype="https://schema.org/Code"> |
| <meta itemprop="url" content="http://example.com/"> |
| <meta itemprop="name" content="FreeMarker Manual"> |
| |
| <!--[if lte IE 9]> |
| <div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please use a modern browser to view this website.</div> |
| <![endif]--><div class="header-top-bg"><div class="site-width header-top"><a class="logo" href="http://example.com" role="banner"> <img itemprop="image" src="logo.png" alt="My Logo"> |
| </a></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">FreeMarker Manual</a><div class="navigation-header"></div></div><div class="site-width breadcrumb-row"><ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="index.html"><span itemprop="name">FreeMarker Manual</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui.html"><span itemprop="name">Programmer's Guide</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config.html"><span itemprop="name">The Configuration</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config_errorhandling.html"><span itemprop="name">Error handling</span></a></li></ul><div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul class="bookmark-list"><li><a href="alphaidx.html">Index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="ref.html">Reference</a></li><li><a href="app_faq.html">FAQ</a></li><li><a href="preface.html#test_target">Bőregér</a></li><li><a href="api/index.html">API</a></li><li><a href="../index.html">Home</a></li></ul></div></div></div> <div class="main-content site-width"> |
| <div class="content-wrapper"> |
| <div id="table-of-contents-wrapper" class="col-left"> |
| <script>var breadcrumb = ["FreeMarker Manual","Programmer\'s Guide","The Configuration","Error handling"];</script> |
| <script src="toc.js?1594338519184"></script> |
| <script src="docgen-resources/main.min.js?1594338519184"></script> |
| </div> |
| <div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="pgui_config_templateloading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="pgui_config_errorhandling" itemprop="headline">Error handling</h1> |
| </div></div><div class="page-menu"> |
| <div class="page-menu-title">Page Contents</div> |
| <ul><li><a class="page-menu-link" href="#autoid_43" data-menu-target="autoid_43">The possible exceptions</a></li><li><a class="page-menu-link" href="#autoid_44" data-menu-target="autoid_44">Customizing the behavior regarding TemplatException-s</a></li><li><a class="page-menu-link" href="#autoid_45" data-menu-target="autoid_45">Explicit error handling in templates</a></li></ul> </div> |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_43">The possible exceptions</h2> |
| |
| |
| <p>The exceptions that can occur regarding FreeMarker could be |
| classified like this:</p> |
| |
| <ul> |
| <li> |
| <p>Exceptions occurring when you configure FreeMarker: |
| Typically you configure FreeMarker only once in your |
| application, when your application initializes itself. Of |
| course, during this, exceptions can occur, as it is obvious from |
| the FreeMarker API...</p> |
| </li> |
| |
| <li> |
| <p>Exceptions occurring when loading and parsing templates: |
| When you call |
| <code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code>, |
| FreeMarker has to load the template file into the memory and |
| parse it (unless the template is already <a href="pgui_config_templateloading.html#pgui_config_templateloading_caching">cached</a> in |
| that <code class="inline-code">Configuration</code> object). During this, two |
| kind of exceptions can occur:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">IOException</code> because the template |
| file was not found, or other I/O problem occurred while |
| trying to read it, for example you have no right to read the |
| file, or there are disk errors. The emitter of these errors |
| is the <a href="pgui_config_templateloading.html"><code>TemplateLoader</code> |
| object</a>, which is plugged into the |
| <code class="inline-code">Configuration</code> object. (For the sake of |
| correctness: When I say ``file'' here, that's a |
| simplification. For example, templates can be stored in a |
| table of a relational database as well. This is the business |
| of the <code class="inline-code">TemplateLoader</code>.)</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">freemarker.core.ParseException</code> |
| because the template file is syntactically incorrect |
| according the rules of the FTL language. The point is that |
| this error occurs when you obtain the |
| <code class="inline-code">Template</code> object |
| (<code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code>), |
| and not when you execute |
| (<code class="inline-code">Template.process(<em class="code-color">...</em>)</code>) |
| the template. This exception is an |
| <code class="inline-code">IOException</code> subclass.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Exceptions occurring when executing (processing) |
| templates, that is, when you call |
| <code class="inline-code">Template.process(<em class="code-color">...</em>)</code>. |
| Two kind of exceptions can occur:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">IOException</code> because there was an |
| error when trying to write into the output writer.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">freemarker.template.TemplatException</code> |
| 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 |
| <code class="inline-code">TemplatException</code> occurs, FreeMarker |
| prints the FTL error message and the stack trace to the |
| output writer with plain text format, and then aborts the |
| template execution by re-throwing the |
| <code class="inline-code">TemplatException</code>, which then you can |
| catch as |
| <code class="inline-code">Template.process(<em class="code-color">...</em>)</code> |
| throws it. But this behavior can be customized. FreeMarker |
| always <a href="pgui_misc_logging.html">logs</a> |
| <code class="inline-code">TemplatException</code>-s.</p> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_44">Customizing the behavior regarding TemplatException-s</h2> |
| |
| |
| <p><code class="inline-code">TemplateException</code>-s thrown during the |
| template processing are handled by the |
| <code class="inline-code">freemarker.template.TemplateExceptionHandler</code> |
| object, which is plugged into the <code class="inline-code">Configuration</code> |
| object with its |
| <code class="inline-code">setTemplateExceptionHandler(<em class="code-color">...</em>)</code> |
| mehod. The <code class="inline-code">TemplateExceptionHandler</code> contains 1 |
| method:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">void handleTemplateException(TemplateException te, Environment env, Writer out) |
| throws TemplateException;</pre></div> |
| |
| <p>Whenever a <code class="inline-code">TemplateException</code> occurs, this |
| method will be called. The exception to handle is passed with the |
| <code class="inline-code">te</code> argument, the runtime environment of the |
| template processing is accessible with the <code class="inline-code">env</code> |
| argument, and the handler can print to the output using the |
| <code class="inline-code">out</code> argument. If the method throws exception |
| (usually it re-throws <code class="inline-code">te</code>), then the template |
| processing will be aborted, and |
| <code class="inline-code">Template.process(<em class="code-color">...</em>)</code> |
| will throw the same exception. If |
| <code class="inline-code">handleTemplateException</code> doesn't throw exception, |
| then template processing continues as if nothing had happen, but the |
| statement that caused the exception will be skipped (see more |
| later). Of course, the handler can still print an error indicator to |
| the output.</p> |
| |
| <p>In any case, before the |
| <code class="inline-code">TemplateExceptionHandler</code> is invoked, FreeMarker |
| will <a href="pgui_misc_logging.html">log</a> the |
| exception.</p> |
| |
| <p>Let's see how FreeMarker skips ``statements'' when the error |
| handler doesn't throw exception, through examples. Assume we are |
| using this template exception handler:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">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); |
| } |
| } |
| } |
| |
| <em>...</em> |
| |
| cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());</pre></div> |
| |
| <p>If an error occurs in an interpolation which is not inside an |
| FTL tag (that is, not enclosed into |
| <code class="inline-code"><#<em class="code-color">...</em>></code> or |
| <code class="inline-code"><@<em class="code-color">...</em>></code>), then |
| the whole interpolation will be skipped. So this template (assuming |
| that <code class="inline-code">badVar</code> is missing from the |
| data-model):</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a${badVar}b</pre></div> |
| |
| <p>will print this if we use the |
| <code class="inline-code">MyTemplateExceptionHandler</code>:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-output">a[ERROR: Expression badVar is undefined on line 1, column 4 in test.ftl.]b</pre></div> |
| |
| <p>This template will print the same (except that the column |
| number will differ...):</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a${"moo" + badVar}b</pre></div> |
| |
| <p>since, as it was written, the whole interpolation is skipped |
| if any error occurs inside it.</p> |
| |
| <p>If an error occurs when evaluating the value of a parameter |
| for a directive call, or if there are other problems with the |
| parameter list, or if an error occurs when evaluating |
| <code class="inline-code"><em class="code-color">exp</em></code> in |
| <code class="inline-code"><@<em class="code-color">exp</em> |
| <em class="code-color">...</em>></code>, or if the value of |
| <code class="inline-code"><em class="code-color">exp</em></code> is not an |
| user-defined directive, then the whole directive call is skipped. |
| For example this:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a<#if badVar>Foo</#if>b</pre></div> |
| |
| <p>will print this:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-output">a[ERROR: Expression badVar is undefined on line 1, column 7 in test.ftl.]b</pre></div> |
| |
| <p>Note that the error occurred in the <code class="inline-code">if</code> |
| start-tag (<code class="inline-code"><#if badVar></code>), but the whole |
| directive call was skipped. Logically, the nested content |
| (<code class="inline-code">Foo</code>) was skipped with this, since the nested |
| content is handled (printed) by the enclosing directive |
| (<code class="inline-code">if</code>).</p> |
| |
| <p>The output will be the same with this (except that the column |
| number will differ...):</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a<#if "foo${badVar}" == "foobar">Foo</#if>b</pre></div> |
| |
| <p>since, as it was written, the whole directive calling will be |
| skipped if any error occurs during the parameter evaluation.</p> |
| |
| <p>The directive call will not be skipped if the error occurs |
| after the execution of the directive was already started. That is, |
| if an error occurs in the nested content:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a |
| <#if true> |
| Foo |
| ${badVar} |
| Bar |
| </#if> |
| c</pre></div> |
| |
| <p>or in the macro definition body:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-template">a |
| <@test /> |
| b |
| <#macro test> |
| Foo |
| ${badVar} |
| Bar |
| </#macro></pre></div> |
| |
| <p>the output will be something like:</p> |
| |
| |
| |
| <div class="code-wrapper"><pre class="code-block code-output">a |
| Foo |
| [ERROR: Expression badVar is undefined on line 4, column 5 in test.ftl.] |
| Bar |
| c</pre></div> |
| |
| <p>FreeMarker comes with these prewritten error handlers:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">TemplateExceptionHandler.DEBUG_HANDLER</code>: |
| Prints stack trace (includes FTL error message and FTL stack |
| trace) and re-throws the exception. This is the default handler |
| (that is, it is initially prugged into all new |
| <code class="inline-code">Configuration</code> objects).</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">TemplateExceptionHandler.HTML_DEBUG_HANDLER</code>: |
| Same as <code class="inline-code">DEBUG_HANDLER</code>, but it formats the |
| stack trace so that it will be readable with Web browsers. |
| Recommended over <code class="inline-code">DEBUG_HANDLER</code> when you |
| generate HTML pages.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">TemplateExceptionHandler.IGNORE_HANDLER</code>: |
| Simply suppresses all exceptions (but remember, FreeMarker will |
| still log them). It does nothing to handle the event. It does |
| not re-throw the exception.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">TemplateExceptionHandler.RETHROW_HANDLER</code>: |
| Simply re-throws all exceptions, it doesn't do anything else. |
| This handler can be good for Web applications (assuming you |
| don't want to continue template processing after exception), |
| because it gives the most control to the Web application over |
| page generation on error conditions (since FreeMarker doesn't |
| print anything to the output about the error). For more |
| information about handling errors in Web applications <a href="app_faq.html#misc.faq.niceErrorPage">see the FAQ</a>.</p> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_45">Explicit error handling in templates</h2> |
| |
| |
| <p>Although it has nothing to do with the FreeMarker |
| configuration (the topic of this chapter), for the sake of |
| completeness it is mentioned here that you can handle errors |
| directly in templates as well. This is usually a bad practice (try |
| keep templates simple and non-technical), but nonetheless necessary |
| sometimes:</p> |
| |
| <ul> |
| <li> |
| <p>Handling missing/null variables: <a href="dgui_template_exp.html#dgui_template_exp_missing">Template Author's Guide/The Template/Expressions/Handling missing values</a></p> |
| </li> |
| |
| <li> |
| <p>Surviving malfunctioning ``portlets'' and such expendable |
| page sections: <a href="ref_directive_attempt.html">Reference/Directive Reference/attempt, recover</a></p> |
| </li> |
| </ul> |
| <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_config_templateloading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc.html"><span>Next</span></a></div></div></div></div> </div> |
| </div> |
| <div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"></div><div class="col-right"><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"> <p class="last-generated"> |
| Last generated: |
| <time itemprop="dateModified" datetime="2020-07-09T23:48:39Z" title="Thursday, July 9, 2020 11:48:39 PM GMT">2020-07-09 23:48:39 GMT</time> </p> |
| <p class="copyright"> |
| © <span itemprop="copyrightYear">1999</span>–2020 |
| <a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a> </p> |
| </div></div></div></body> |
| </html> |