| <!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 - Apache 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="Apache FreeMarker Manual"> |
| <meta property="og:title" content="Error handling"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/pgui_config_errorhandling.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/pgui_config_errorhandling.html"> |
| <link rel="icon" href="favicon.png" type="image/png"> |
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:500,700,400,300|Droid+Sans+Mono"> |
| <link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1707770044859"> |
| <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookie-bar/cookiebar-latest.min.js"></script> |
| </head> |
| <body itemscope itemtype="https://schema.org/Code"> |
| <meta itemprop="url" content="https://freemarker.apache.org/docs/"> |
| <meta itemprop="name" content="Apache FreeMarker Manual"> |
| |
| <!--[if lte IE 9]> |
| <div class="oldBrowserWarning" style="display: block"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <![endif]--> <div class="oldBrowserWarning"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <div class="header-top-bg"><div class="site-width header-top"><div id="hamburger-menu" role="button"></div> <div class="logo"> |
| <a href="https://freemarker.apache.org" role="banner"><img itemprop="image" src="logo.png" alt="FreeMarker"></a> </div> |
| <ul class="tabs"><li><a href="https://freemarker.apache.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="https://freemarker.apache.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://issues.apache.org/jira/projects/FREEMARKER" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="https://freemarker.apache.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">Manual</a><div class="navigation-header"></div><form method="get" class="search-form" action="search-results.html"><fieldset><legend class="sr-only">Search form</legend><label for="search-field" class="sr-only">Search query</label><input id="search-field" name="q" type="search" class="search-input" placeholder="Search" spellcheck="false" autocorrect="off" autocomplete="off"><button type="submit" class="search-btn"><span class="sr-only">Search</span></button></fieldset></form></div><div class="site-width breadcrumb-row"> <div class="breadcrumbs"> |
| <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">Apache 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> |
| <div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</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 = ["Apache FreeMarker Manual","Programmer\'s Guide","The Configuration","Error handling"];</script> |
| <script src="toc.js?1707770044859"></script> |
| <script src="docgen-resources/main.min.js?1707770044859"></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_config_templateconfigurations.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 |
| TemplateException-s</a></li><li><a class="page-menu-link" href="#autoid_45" data-menu-target="autoid_45">TemplateException logging</a></li><li><a class="page-menu-link" href="#autoid_46" data-menu-target="autoid_46">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.</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 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, |
| these kind of exceptions can occur:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">TemplateNotFoundException</code> because |
| the requested template doesn't exist. Note this extends |
| <code class="inline-code">IOException</code>.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">freemarker.core.ParseException</code> |
| because the template is syntactically incorrect according |
| the rules of the FTL language. Note 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>), |
| not later when you execute |
| (<code class="inline-code">Template.process(<em class="code-color">...</em>)</code>) |
| the template. . Note this extends |
| <code class="inline-code">IOException</code> (legacy).</p> |
| </li> |
| |
| <li> |
| <p>Any other kind of <code class="inline-code">IOException</code> |
| because an error has occurred while reading an existing |
| template. For example you have no right to read the file, or |
| the connection through which you read the template is |
| broken. The emitter of these 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.</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.TemplateException</code> |
| because other problem occurred while executing the template. |
| For example, a frequent error is referring to a variable |
| that doesn't exist in the data-model. By default, when a |
| <code class="inline-code">TemplateException</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">TemplateException</code>, which then you can |
| catch as |
| <code class="inline-code">Template.process(<em class="code-color">...</em>)</code> |
| throws it. This behavior can be customized, and in fact, it |
| should be; see the recommended configuration <a href="pgui_quickstart_createconfiguration.html">here</a>. |
| By default FreeMarker also <a href="pgui_misc_logging.html">logs</a> |
| <code class="inline-code">TemplateException</code>-s.</p> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_44">Customizing the behavior regarding |
| TemplateException-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> |
| method. These are the <code class="inline-code">TemplateExceptionHandler</code> |
| implementations with FreeMarker comes with:</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, |
| however, you should be careful not using it in production |
| environment, as it shows technical information about your |
| system.</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, but it should only be used for development |
| as it shows technical information about your system.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">TemplateExceptionHandler.IGNORE_HANDLER</code>: |
| Simply suppresses all exceptions (though FreeMarker will still |
| log them if |
| <code class="inline-code">Configuration.getLogTemplateExceptions</code> is |
| <code class="inline-code">true</code>). 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 should be used in most applications today. It doesn't print |
| anything to the output about the error, which makes it safe, and |
| the developers can still get the error details from the logs. |
| It's not as convenient during template development as |
| <code class="inline-code">HTML_DEBUG_HANDLER</code> or |
| <code class="inline-code">DEBUG_HANDLER</code> though. For more information |
| about handling errors in Web applications <a href="app_faq.html#misc.faq.niceErrorPage">see the FAQ</a>.</p> |
| </li> |
| </ul> |
| |
| <p>You can also write a custom |
| <code class="inline-code">TemplateExceptionHandler</code> by implementing that |
| interface, which contains this method:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">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 in the |
| <code class="inline-code">te</code> argument, the runtime environment of the |
| template processing is in 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 this 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>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-block role-unspecified"> |
| <pre class="code-block-body">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-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a${badVar}b</pre> </div> |
| |
| |
| <p>will print this if we use the |
| <code class="inline-code">MyTemplateExceptionHandler</code>:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">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-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a${"moo" + badVar}b</pre> </div> |
| |
| |
| <p>because 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-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a<#if badVar>Foo</#if>b</pre> </div> |
| |
| |
| <p>will print this:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">a[ERROR: Expression badVar is undefined on line 1, column 7 in test.ftlh.]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-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a<#if "foo${badVar}" == "foobar">Foo</#if>b</pre> </div> |
| |
| |
| <p>because 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-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a |
| <#if true> |
| Foo |
| ${badVar} |
| Bar |
| </#if> |
| c</pre> </div> |
| |
| |
| <p>or in the macro definition body:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body">a |
| <@test /> |
| b |
| <#macro test> |
| Foo |
| ${badVar} |
| Bar |
| </#macro></pre> </div> |
| |
| |
| <p>the output will be something like:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">a |
| Foo |
| [ERROR: Expression badVar is undefined on line 4, column 5 in test.ftlh.] |
| Bar |
| c</pre> </div> |
| |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_45">TemplateException logging</h2> |
| |
| |
| <p>By default FreeMarker <a href="pgui_misc_logging.html">logs</a> all |
| <code class="inline-code">TemplateException</code>-s under the |
| <code class="inline-code">freemarker.runtime</code> log category, even when it |
| will throw it at you from its public API. As logging has become |
| common practice in Java applications, this usually leads to double |
| logging of exceptions now, so it's recommended to disable this |
| legacy behavior by |
| <code class="inline-code">cfg.setLogTemplateExceptions(false)</code> (or |
| <code class="inline-code">log_template_exceptions=false</code>) where you |
| configure FreeMarker.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_46">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's mentioned here that you can handle errors directly |
| inside the templates as well:</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>Substituting failing but expendable page sections: <a href="ref_directive_attempt.html">Template Language 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_config_templateconfigurations.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 class="column"><h3 class="column-header">Overview</h3><ul><li><a href="https://freemarker.apache.org/">What is FreeMarker?</a></li><li><a href="https://freemarker.apache.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="app_faq.html">FAQ</a></li><li><a itemprop="license" href="app_license.html">License</a></li><li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a></li></ul></div><div class="column"><h3 class="column-header">Often used / Reference</h3><ul><li><a href="https://try.freemarker.apache.org/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li><li><a href="api/freemarker/core/Configurable.html#setSetting-java.lang.String-java.lang.String-">Configuration settings</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/apache/freemarker">Github project page</a></li><li><a href="https://issues.apache.org/jira/projects/FREEMARKER">Report a bug</a></li><li><a href="https://freemarker.apache.org/report-security-vulnerabilities.html">Report security vulnerability</a></li><li><a href="https://stackoverflow.com/questions/ask?tags=freemarker">Get help on StackOverflow</a></li><li><a href="https://twitter.com/freemarker">Announcements on Twitter</a></li><li><a href="https://freemarker.apache.org/mailing-lists.html">Discuss on mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/apache/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="https://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><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="2024-02-12T20:34:04Z" title="Monday, February 12, 2024 at 8:34:04 PM Greenwich Mean Time">2024-02-12 20:34:04 GMT</time>, for Freemarker 2.3.32 </p> |
| <p class="copyright"> |
| © <span itemprop="copyrightYear">1999</span>–2024 |
| <a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a>. Apache FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners. </p> |
| </div></div></div></body> |
| </html> |