| <!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>Bean wrapper - 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="Bean wrapper"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/pgui_misc_beanwrapper.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/pgui_misc_beanwrapper.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_misc.html"><span itemprop="name">Miscellaneous</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_misc_beanwrapper.html"><span itemprop="name">Bean wrapper</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","Miscellaneous","Bean wrapper"];</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_misc_multithreading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc_logging.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="pgui_misc_beanwrapper" itemprop="headline">Bean wrapper</h1> |
| </div></div><div class="page-menu"> |
| <div class="page-menu-title">Page Contents</div> |
| <ul><li><a class="page-menu-link" href="#beanswrapper_hash" data-menu-target="beanswrapper_hash">TemplateHashModel functionality</a></li><li><a class="page-menu-link" href="#autoid_54" data-menu-target="autoid_54">A word on security</a></li><li><a class="page-menu-link" href="#autoid_55" data-menu-target="autoid_55">TemplateScalarModel functionality</a></li><li><a class="page-menu-link" href="#autoid_56" data-menu-target="autoid_56">TemplateNumberModel functionality</a></li><li><a class="page-menu-link" href="#autoid_57" data-menu-target="autoid_57">TemplateCollectionModel functionality</a></li><li><a class="page-menu-link" href="#autoid_58" data-menu-target="autoid_58">TemplateSequenceModel functionality</a></li><li><a class="page-menu-link" href="#beanswrapper_method" data-menu-target="beanswrapper_method">TemplateMethodModel functionality</a></li><li><a class="page-menu-link" href="#autoid_59" data-menu-target="autoid_59">Unwrapping rules</a></li><li><a class="page-menu-link" href="#autoid_60" data-menu-target="autoid_60">Accessing static methods</a></li><li><a class="page-menu-link" href="#jdk_15_enums" data-menu-target="jdk_15_enums">Accessing enums</a></li></ul> </div> <div class="callout note"> |
| <strong class="callout-label">Note:</strong> |
| |
| <p>Using <code class="inline-code">BeansWrapper</code> directly is not |
| recommended anymore. Use its subclass, |
| <code class="inline-code">DefaultObjectWrapper</code> instead, though by ensuring |
| that its <code class="inline-code">incompatibleImprovements</code> property is at |
| least 2.3.22. <code class="inline-code">DefaultObjectWrapper</code> gives cleaner |
| data-model (less confusing multi-type FTL values) and is usually |
| faster. <a href="pgui_datamodel_objectWrapper.html#pgui_datamodel_defaultObjectWrapper">See more |
| about DefaultObjectWrapper here...</a></p> |
| </div> |
| <p>The <code class="inline-code">freemarker.ext.beans.BeansWrapper</code> is an |
| <a href="pgui_datamodel_objectWrapper.html">object wrapper</a> |
| that was originally added to FreeMarker so arbitrary POJO-s (Plain Old |
| Java Objects) can be wrapped into <code class="inline-code">TemplateModel</code> |
| interfaces. Since then it has became the normal way of doing things, |
| and in fact the <code class="inline-code">DefaultObjectWrapper</code> itself is a |
| <code class="inline-code">BeansWrapper</code> extension. So everything described |
| here goes for the <code class="inline-code">DefaultObjectWrapper</code> too, except |
| that the <code class="inline-code">DefaultObjectWrapper</code> will wrap |
| <code class="inline-code">String</code>, <code class="inline-code">Number</code>, |
| <code class="inline-code">Date</code>, <code class="inline-code">array</code>, |
| <code class="inline-code">Collection</code> (like <code class="inline-code">List</code>), |
| <code class="inline-code">Map</code>, <code class="inline-code">Boolean</code> and |
| <code class="inline-code">Iterator</code> objects with the |
| <code class="inline-code">freemarker.template.Simple<em class="code-color">Xxx</em></code> |
| classes, and W3C DOM nodes with |
| <code class="inline-code">freemarker.ext.dom.NodeModel</code> (<a href="xgui.html">more about wrapped W3C DOM...</a>), so for those the |
| above described rules doesn't apply.</p><p>You will want to use <code class="inline-code">BeansWrapper</code> instead of |
| <code class="inline-code">DefaultObjectWrapper</code> when any of these |
| stands:</p><ul> |
| <li> |
| <p>The <code class="inline-code">Collection</code>-s and |
| <code class="inline-code">Map</code>-s of the model should be allowed to be |
| modified during template execution. |
| (<code class="inline-code">DefaultObjectWrapper</code> prevents that, since it |
| creates a copy of the collections when they are wrapped, and the |
| copies will be read-only.)</p> |
| </li> |
| |
| <li> |
| <p>If the identity of the <code class="inline-code">array</code>, |
| <code class="inline-code">Collection</code> and <code class="inline-code">Map</code> objects |
| must be kept when they are passed to a wrapped object's method in |
| the template. That is, if those methods must get exactly the same |
| object that was earlier wrapped.</p> |
| </li> |
| |
| <li> |
| <p>If the Java API of the earlier listed classes |
| (<code class="inline-code">String</code>, <code class="inline-code">Map</code>, |
| <code class="inline-code">List</code> ...etc) should be visible for the |
| templates. Even with <code class="inline-code">BeansWrapper</code>, they are not |
| visible by default, but it can be achieved by setting the exposure |
| level (see later). Note that this is usually a bad practice; try |
| to use <a href="ref_builtins.html">the built-ins</a> (like |
| <code class="inline-code">foo?size</code>, <code class="inline-code">foo?upper_case</code>, |
| <code class="inline-code">foo?replace('_', '-')</code> ...etc) instead of the |
| Java API.</p> |
| </li> |
| </ul><p>Below is a summary of the <code class="inline-code">TemplateModel</code>-s |
| that the <code class="inline-code">BeansWrapper</code> creates. Let's assume that |
| the object is called <code class="inline-code">obj</code> before wrapping, and |
| <code class="inline-code">model</code> after wrapping for the sake of the following |
| discussion.</p> |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="beanswrapper_hash">TemplateHashModel functionality</h2> |
| |
| |
| <p>Every object will be wrapped into a |
| <code class="inline-code">TemplateHashModel</code> that will expose JavaBeans |
| properties and methods of the object. This way, you can use |
| <code class="inline-code">model.foo</code> in the template to invoke |
| <code class="inline-code">obj.getFoo()</code> or <code class="inline-code">obj.isFoo()</code> |
| methods. (Note that public fields are not visible directly; you must |
| write a getter method for them.) Public methods are also retrievable |
| through the hash model as template method models, therefore you can |
| use the <code class="inline-code">model.doBar()</code> to invoke |
| <code class="inline-code">object.doBar()</code>. More on this on discussion of |
| method model functionality.</p> |
| |
| <p>If the requested key can not be mapped to a bean property or |
| method, the framework will attempt to locate the so-called "generic |
| get method", that is a method with signature public |
| <code class="inline-code"><em class="code-color">any-return-type</em> |
| get(String)</code> or public |
| <code class="inline-code"><em class="code-color">any-return-type</em> |
| get(Object)</code> and invoke that method with the requested key. |
| Note that this allows convenient access to mappings in a |
| <code class="inline-code">java.util.Map</code> and similar classes - as long as |
| the keys of the map are <code class="inline-code">String</code>s and some property |
| or method name does not shadow the mapping. (There is a solution to |
| avoid shadowing, read on.) Also note that the models for |
| <code class="inline-code">java.util.ResourceBundle</code> objects use the |
| <code class="inline-code">getObject(String)</code> as the generic get |
| method.</p> |
| |
| <p>If you call <code class="inline-code">setExposeFields(true)</code> on a |
| <code class="inline-code">BeansWrapper</code> instance, it will also expose |
| public, non-static fields of classes as hash keys and values. I.e. |
| if <code class="inline-code">foo</code> is a public, non-static field of the class |
| <code class="inline-code">Bar</code>, and <code class="inline-code">bar</code> is a template |
| variable wrapping an instance of <code class="inline-code">Bar</code>, then |
| <code class="inline-code">bar.foo</code> expression will evaluate as the value of |
| the field <code class="inline-code">foo</code> of the <code class="inline-code">bar</code> |
| object. The public fields in all superclasses of the class are also |
| exposed.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_54">A word on security</h2> |
| |
| |
| <p>By default, you will not be able to access several methods |
| that are considered not safe for templating. For instance, you can't |
| use synchronization methods (<code class="inline-code">wait</code>, |
| <code class="inline-code">notify</code>, <code class="inline-code">notifyAll</code>), thread and |
| thread group management methods (<code class="inline-code">stop</code>, |
| <code class="inline-code">suspend</code>, <code class="inline-code">resume</code>, |
| <code class="inline-code">setDaemon</code>, <code class="inline-code">setPriority</code>), |
| reflection (<code class="inline-code">Field</code> |
| <code class="inline-code">set<em class="code-color">Xxx</em></code> methods, |
| <code class="inline-code">Method.invoke</code>, |
| <code class="inline-code">Constructor.newInstance</code>, |
| <code class="inline-code">Class.newInstance</code>, |
| <code class="inline-code">Class.getClassLoader</code> etc.) and various dangerous |
| methods in <code class="inline-code">System</code> and <code class="inline-code">Runtime</code> |
| classes (<code class="inline-code">exec</code>, <code class="inline-code">exit</code>, |
| <code class="inline-code">halt</code>, <code class="inline-code">load</code>, etc.). The |
| <code class="inline-code">BeansWrapper</code> has several security levels (called |
| "levels of method exposure"), and the default called |
| <code class="inline-code">EXPOSE_SAFE</code> is probably suited for most |
| applications. There is a no-safeguard level called |
| <code class="inline-code">EXPOSE_ALL</code> that allows you to call even the above |
| unsafe methods, and a strict level |
| <code class="inline-code">EXPOSE_PROPERTIES_ONLY</code> that will expose only bean |
| property getters. Finally, there is a level named |
| <code class="inline-code">EXPOSE_NOTHING</code> that will expose no properties and |
| no methods. The only data you will be able to access through hash |
| model interface in this case are items in maps and resource bundles, |
| as well as objects returned from a call to generic |
| <code class="inline-code">get(Object)</code> or <code class="inline-code">get(String)</code> |
| methods - provided the affected objects have such method.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_55">TemplateScalarModel functionality</h2> |
| |
| |
| <p>Models for <code class="inline-code">java.lang.String</code> objects will |
| implement <code class="inline-code">TemplateScalarModel</code> whose |
| <code class="inline-code">getAsString()</code> method simply delegates to |
| <code class="inline-code">toString()</code>. Note that wrapping |
| <code class="inline-code">String</code> objects into Bean wrappers provides much |
| more functionality than just them being scalars: because of the hash |
| interface described above, the models that wrap |
| <code class="inline-code">String</code>s also provide access to all |
| <code class="inline-code">String</code> methods (<code class="inline-code">indexOf</code>, |
| <code class="inline-code">substring</code>, etc.), though most of them has native |
| FreeMarker equivalent which are better to use |
| (<code class="inline-code">s?index_of(n)</code>, |
| <code class="inline-code">s[start..<end]</code>, etc).</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_56">TemplateNumberModel functionality</h2> |
| |
| |
| <p>Model wrappers for objects that are instances of |
| <code class="inline-code">java.lang.Number</code> implement |
| <code class="inline-code">TemplateNumberModel</code> whose |
| <code class="inline-code">getAsNumber()</code> method returns the wrapped number |
| object. Note that wrapping <code class="inline-code">Number</code> objects into |
| Bean wrappers provides much more functionality than just them being |
| number models: because of the hash interface described above, the |
| models that wrap <code class="inline-code">Number</code>s also provide access to |
| all their methods.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_57">TemplateCollectionModel functionality</h2> |
| |
| |
| <p>Model wrappers for native Java arrays and all classes that |
| implement <code class="inline-code">java.util.Collection</code> will implement |
| <code class="inline-code">TemplateCollectionModel</code> and thus gain the |
| additional capability of being usable through |
| <code class="inline-code">list</code> directive.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_58">TemplateSequenceModel functionality</h2> |
| |
| |
| <p>Model wrappers for native Java arrays and all classes that |
| implement <code class="inline-code">java.util.List</code> will implement |
| <code class="inline-code">TemplateSequenceModel</code> and thus their elements |
| will be accessible by index using the <code class="inline-code">model[i]</code> |
| syntax. You can also query the length of the array or the size of |
| the list using the <code class="inline-code">model?size</code> built-in.</p> |
| |
| <p>Also, every method that takes a single parameter that is |
| assignable through reflective method invocation from a |
| <code class="inline-code">java.lang.Integer</code> (these are |
| <code class="inline-code">int</code>, <code class="inline-code">long</code>, |
| <code class="inline-code">float</code>, <code class="inline-code">double</code>, |
| <code class="inline-code">java.lang.Object</code>, |
| <code class="inline-code">java.lang.Number</code>, and |
| <code class="inline-code">java.lang.Integer</code>) also implements this |
| interface. What this means is that you have a convenient way for |
| accessing the so-called indexed bean properties: |
| <code class="inline-code">model.foo[i]</code> will translate into |
| <code class="inline-code">obj.getFoo(i)</code>.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="beanswrapper_method">TemplateMethodModel functionality</h2> |
| |
| |
| <p>All methods of an object are represented as |
| <code class="inline-code">TemplateMethodModelEx</code> objects accessible using a |
| hash key with method name on their object's model. When you call a |
| method using |
| <code class="inline-code">model.<em class="code-color">method</em>(<em class="code-color">arg1</em>, |
| <em class="code-color">arg2</em>, |
| <em class="code-color">...</em>)</code> the arguments are passed |
| to the method as template models. The method will first try to |
| unwrap them - see below for details about unwrapping. These |
| unwrapped arguments are then used for the actual method call. In |
| case the method is overloaded, the most specific method will be |
| selected using the same rules that are used by the Java compiler to |
| select a method from several overloaded methods. In case that no |
| method signature matches the passed parameters, or that no method |
| can be chosen without ambiguity, a |
| <code class="inline-code">TemplateModelException</code> is thrown.</p> |
| |
| <p>Methods of return type <code class="inline-code">void</code> return |
| <code class="inline-code">TemplateModel.NOTHING</code>, so they can be safely |
| called with the <code class="inline-code">${obj.method(args)}</code> |
| syntax.</p> |
| |
| <p>Models for instances of <code class="inline-code">java.util.Map</code> also |
| implement <code class="inline-code">TemplateMethodModelEx</code> as a means for |
| invoking their <code class="inline-code">get()</code> method. As it was discussed |
| previously, you can use the hash functionality to access the "get" |
| method as well, but it has several drawbacks: it's slower because |
| first property and method names are checked for the key; keys that |
| conflict with property and method names will be shadowed by them; |
| finally you can use <code class="inline-code">String</code> keys only with that |
| approach. In contrast, invoking <code class="inline-code">model(key)</code> |
| translates to <code class="inline-code">model.get(key)</code> directly: it's |
| faster because there's no property and method name lookup; it is |
| subject to no shadowing; and finally it works for non-String keys |
| since the argument is unwrapped just as with ordinary method calls. |
| In effect, <code class="inline-code">model(key)</code> on a <code class="inline-code">Map</code> |
| is equal to <code class="inline-code">model.get(key)</code>, only shorter to |
| write.</p> |
| |
| <p>Models for <code class="inline-code">java.util.ResourceBundle</code> also |
| implement <code class="inline-code">TemplateMethodModelEx</code> as a convenient |
| way of resource access and message formatting. A single-argument |
| call to a bundle will retrieve the resource with the name that |
| corresponds to the <code class="inline-code">toString()</code> value of the |
| unwrapped argument. A multiple-argument call to a bundle will also |
| retrieve the resource with the name that corresponds to the |
| <code class="inline-code">toString()</code> value of the unwrapped argument, but |
| it will use it as a format pattern and pass it to |
| <code class="inline-code">java.text.MessageFormat</code> using the unwrapped |
| values of second and later arguments as formatting parameters. |
| <code class="inline-code">MessageFormat</code> objects will be initialized with |
| the locale of the bundle that originated them.</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_59">Unwrapping rules</h2> |
| |
| |
| <p>When invoking a Java method from a template, its arguments |
| need to be converted from template models back to Java objects. |
| Assuming that the target type (the declared type of the method's |
| formal parameter) is denoted as <code class="inline-code">T</code>, the following |
| rules are tried in the following order:</p> |
| |
| <ul> |
| <li> |
| <p>If the model is the null model for this wrapper, Java |
| <code class="inline-code">null</code> is returned.</p> |
| </li> |
| |
| <li> |
| <p>If the model implements |
| <code class="inline-code">AdapterTemplateModel</code>, the result of |
| <code class="inline-code">model.getAdaptedObject(T)</code> is returned if it |
| is instance of <code class="inline-code">T</code> or it is a number and can be |
| converted to <code class="inline-code">T</code> using numeric coercion as |
| described three bullets lower. <span class="marked-for-programmers">All |
| models created by the BeansWrapper are themselves |
| AdapterTemplateModel implementations, so unwrapping a model that |
| was created by BeansWrapper for an underlying Java object always |
| yields the original Java object.</span></p> |
| </li> |
| |
| <li> |
| <p>If the model implements the deprecated |
| <code class="inline-code">WrapperTemplateModel</code>, the result of |
| <code class="inline-code">model.getWrappedObject()</code> is returned if it is |
| instance of <code class="inline-code">T</code> or it is a number and can be |
| converted to <code class="inline-code">T</code> using numeric coercion as |
| described two bullets lower.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is |
| <code class="inline-code">java.lang.String</code>, then if model implements |
| <code class="inline-code">TemplateScalarModel</code> its string value is |
| returned. <span class="marked-for-programmers">Note that if the model |
| doesn't implement TemplateScalarModel we don't attempt to |
| automatically convert the model to string using |
| String.valueOf(model). You'll have to use the ?string built-in |
| explicitly to pass non-scalars as strings.</span></p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is a primitive numeric type or |
| <code class="inline-code">java.lang.Number</code> is assignable from |
| <code class="inline-code">T</code>, and model implements |
| <code class="inline-code">TemplateNumberModel</code>, then its numeric value |
| is returned if it is instance of <code class="inline-code">T</code> or its |
| boxing type (if <code class="inline-code">T</code> is primitive type). |
| Otherwise, if <code class="inline-code">T</code> is a built-in Java numeric |
| type (primitive type or a standard subclass of |
| <code class="inline-code">java.lang.Number</code>, including |
| <code class="inline-code">BigInteger</code> and <code class="inline-code">BigDecimal</code>) |
| a new object of class <code class="inline-code">T</code> or its boxing type is |
| created with the number model's appropriately coerced |
| value.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is <code class="inline-code">boolean</code> or |
| <code class="inline-code">java.lang.Boolean</code>, and model implements |
| <code class="inline-code">TemplateBooleanModel</code>, then its boolean value |
| is returned.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is |
| <code class="inline-code">java.util.Map</code> and the model implements |
| <code class="inline-code">TemplateHashModel</code>, then a special Map |
| representation of the hash model is returned.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is |
| <code class="inline-code">java.util.List</code> and the model implements |
| <code class="inline-code">TemplateSequenceModel</code>, then a special List |
| representation of the sequence model is returned.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is |
| <code class="inline-code">java.util.Set</code> and the model implements |
| <code class="inline-code">TemplateCollectionModel</code>, then a special Set |
| representation of the collection model is returned.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is |
| <code class="inline-code">java.util.Collection</code> or |
| <code class="inline-code">java.lang.Iterable</code> and the model implements |
| either <code class="inline-code">TemplateCollectionModel</code> or |
| <code class="inline-code">TemplateSequenceModel</code>, then a special Set or |
| List representation of the collection or sequence model |
| (respectively) is returned.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is a Java array type and the model |
| implements <code class="inline-code">TemplateSequenceModel</code>, then a new |
| array of the specified type is created and its elements |
| unwrapped into the array recursively using the array's component |
| type as <code class="inline-code">T</code>.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">T</code> is <code class="inline-code">char</code> or |
| <code class="inline-code">java.lang.Character</code>, and model implements |
| <code class="inline-code">TemplateScalarModel</code>, and its string |
| representation contains exactly one character, then a |
| <code class="inline-code">java.lang.Character</code> with that value is |
| retured.</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">java.util.Date</code> is assignable from |
| <code class="inline-code">T</code>, and model implements |
| <code class="inline-code">TemplateDateModel</code>, and its date value is |
| instance of <code class="inline-code">T</code>, then its date value is |
| returned.</p> |
| </li> |
| |
| <li> |
| <p>If model is a number model, and its numeric value is |
| instance of <code class="inline-code">T</code>, the numeric value is returned. |
| <span class="marked-for-programmers">You can have a custom subclass of |
| java.lang.Number that implements a custom interface, and T might |
| be that interface. (*)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a date model, and its date value is instance |
| of <code class="inline-code">T</code>, the date value is returned. <span class="marked-for-programmers">Similar consideration as for |
| (*)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a scalar model, and <code class="inline-code">T</code> is |
| assignable from <code class="inline-code">java.lang.String</code>, the string |
| value is returned. <span class="marked-for-programmers">This covers |
| cases when T is java.lang.Object, java.lang.Comparable, and |
| java.io.Serializable (**)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a boolean model, and <code class="inline-code">T</code> is |
| assignable from <code class="inline-code">java.lang.Boolean</code>, the |
| boolean value is returned. <span class="marked-for-programmers">Same as |
| (**)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a hash model, and <code class="inline-code">T</code> is |
| assignable from |
| <code class="inline-code">freemarker.ext.beans.HashAdapter</code>, a hash |
| adapter is returned. <span class="marked-for-programmers">Same as |
| (**)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a sequence model, and <code class="inline-code">T</code> is |
| assignable from |
| <code class="inline-code">freemarker.ext.beans.SequenceAdapter</code>, a |
| sequence adapter is returned. <span class="marked-for-programmers">Same |
| as (**)</span></p> |
| </li> |
| |
| <li> |
| <p>If model is a collection model, and <code class="inline-code">T</code> |
| is assignable from |
| <code class="inline-code">freemarker.ext.beans.SetAdapter</code>, a set |
| adapter for the collection is returned. <span class="marked-for-programmers">Same as (**)</span></p> |
| </li> |
| |
| <li> |
| <p>If the model is instance of <code class="inline-code">T</code>, the |
| model itself is returned. <span class="marked-for-programmers">This |
| covers the case where the method explicitly declared a |
| FreeMarker-specific model interface, as well as allows returning |
| directive, method and transform models when java.lang.Object is |
| requested.</span></p> |
| </li> |
| |
| <li> |
| <p>An exception signifying no conversion is possible is |
| thrown.</p> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_60">Accessing static methods</h2> |
| |
| |
| |
| |
| <p>The <code class="inline-code">TemplateHashModel</code> returned from |
| <code class="inline-code">BeansWrapper.getStaticModels()</code> can be used to |
| create hash models for accessing static methods and fields of an |
| arbitrary class.</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); |
| TemplateHashModel staticModels = wrapper.getStaticModels(); |
| TemplateHashModel fileStatics = |
| (TemplateHashModel) staticModels.get("java.io.File");</pre> </div> |
| |
| |
| <p>And you will get a template hash model that exposes all static |
| methods and static fields (both final and non-final) of the |
| <code class="inline-code">java.lang.System</code> class as hash keys. Suppose that |
| you put the previous model in your root model:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">root.put("File", fileStatics);</pre> </div> |
| |
| |
| <p>From now on, you can use <code class="inline-code">${File.SEPARATOR}</code> |
| to insert the file separator character into your template, or you |
| can even list all roots of your file system by:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#list File.listRoots() as fileSystemRoot>...</#list></pre> </div> |
| |
| |
| <p>Of course, you must be aware of the potential security issues |
| this model brings.</p> |
| |
| <p>You can even give the template authors complete freedom over |
| which classes' static methods they use by placing the static models |
| hash into your template root model with</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">root.put("statics", BeansWrapper.getDefaultInstance().getStaticModels());</pre> </div> |
| |
| |
| <p>This object exposes just about any class' static methods if |
| it's used as a hash with class name as the key. You can then use |
| expression like |
| <code class="inline-code">${statics["java.lang.System"].currentTimeMillis()}</code> |
| in your template. Note, however that this has even more security |
| implications, as someone could even invoke |
| <code class="inline-code">System.exit()</code> using this model if the method |
| exposure level is weakened to <code class="inline-code">EXPOSE_ALL</code>.</p> |
| |
| <p>Note that in above examples, we always use the default |
| <code class="inline-code">BeansWrapper</code> instance. This is a convenient |
| static wrapper instance that you can use in most cases. You are also |
| free to create your own <code class="inline-code">BeansWrapper</code> instances |
| and use them instead especially when you want to modify some of its |
| characteristics (like model caching, security level, or the null |
| model representation).</p> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="jdk_15_enums">Accessing enums</h2> |
| |
| |
| |
| |
| <p>The <code class="inline-code">TemplateHashModel</code> returned from |
| <code class="inline-code">BeansWrapper.getEnumModels()</code> can be used to |
| create hash models for accessing values of enums. (An attempt to |
| invoke this method on an earlier JRE will result in an |
| <code class="inline-code">UnsupportedOperationException</code>.)</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); |
| TemplateHashModel enumModels = wrapper.getEnumModels(); |
| TemplateHashModel roundingModeEnums = |
| (TemplateHashModel) enumModels.get("java.math.RoundingMode");</pre> </div> |
| |
| |
| <p>And you will get a template hash model that exposes all enum |
| values of the <code class="inline-code">java.math.RoundingMode</code> class as |
| hash keys. Suppose that you put the previous model in your root |
| model:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">root.put("RoundingMode", roundingModeEnums);</pre> </div> |
| |
| |
| <p>From now on, you can use <code class="inline-code">RoundingMode.UP</code> as |
| an expression to reference the <code class="inline-code">UP</code> enum value in |
| your template.</p> |
| |
| <p>You can even give the template authors complete freedom over |
| which enum classes they use by placing the enum models hash into |
| your template root model with</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body">root.put("enums", BeansWrapper.getDefaultInstance().getEnumModels());</pre> </div> |
| |
| |
| <p>This object exposes any enum class if it's used as a hash with |
| class name as the key. You can then use expression like |
| <code class="inline-code">${enums["java.math.RoundingMode"].UP}</code> in your |
| template.</p> |
| |
| <p>The exposed enum values can be used as scalars (they'll |
| delegate to their <code class="inline-code">toString()</code> method), and can be |
| used in equality and inequality comparisons as well.</p> |
| |
| <p>Note that in above examples, we always use the default |
| <code class="inline-code">BeansWrapper</code> instance. This is a convenient |
| static wrapper instance that you can use in most cases. You are also |
| free to create your own <code class="inline-code">BeansWrapper</code> instances |
| and use them instead especially when you want to modify some of its |
| characteristics (like model caching, security level, or the null |
| model representation).</p> |
| <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_misc_multithreading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc_logging.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> |