| <!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>Object wrappers - 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="Object wrappers"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="http://example.com/pgui_datamodel_objectWrapper.html"> |
| <link rel="canonical" href="http://example.com/pgui_datamodel_objectWrapper.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_datamodel.html"><span itemprop="name">The Data Model</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_datamodel_objectWrapper.html"><span itemprop="name">Object wrappers</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 Data Model","Object wrappers"];</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_datamodel_node.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="pgui_datamodel_objectWrapper" itemprop="headline">Object wrappers</h1> |
| </div></div><p>When you add something to a container, it may receive any java |
| object as a parameter, not necessarily a |
| <code class="inline-code">TemplateModel</code>, as you could see in the FreeMarker |
| API. This is because the container implementation can silently replace |
| that object with the appropriate <code class="inline-code">TemplateModel</code> |
| object. For example if you add a <code class="inline-code">String</code> to the |
| container, perhaps it will be replaced with a |
| <code class="inline-code">SimpleScalar</code> instance which stores the same |
| text.</p><p>As for when the replacement occurs, it's the business of the |
| container in question (i.e. the business of the class that implements |
| the container interface), but it must happen at the latest when you |
| get the subvariable, as the getter methods (according to the |
| interfaces) return <code class="inline-code">TemplateModel</code>, not |
| <code class="inline-code">Object</code>. For example, <code class="inline-code">SimpleHash</code>, |
| <code class="inline-code">SimpleSequence</code> and |
| <code class="inline-code">SimpleCollection</code> use the laziest strategy; they |
| replace a non-<code class="inline-code">TemplateModel</code> subvariable with an |
| appropriate <code class="inline-code">TemplateModel</code> object when you get the |
| subvariable for the first time.</p><p>As for what java objects can be replaced, and with what |
| <code class="inline-code">TemplateModel</code> implementations, it is either handled |
| by the container implementation itself, or it delegates this to an |
| <code class="inline-code">ObjectWrapper</code> instance. |
| <code class="inline-code">ObjectWrapper</code> is an interface that specifies one |
| method: <code class="inline-code">TemplateModel wrap(java.lang.Object obj)</code>. |
| You pass in an <code class="inline-code">Object</code>, and it returns the |
| corresponding <code class="inline-code">TemplateModel</code> object, or throws a |
| <code class="inline-code">TemplateModelException</code> if this is not possible. The |
| replacement rules are coded into the <code class="inline-code">ObjectWrapper</code> |
| implementation.</p><p>The most important <code class="inline-code">ObjectWrapper</code> |
| implementations that the FreeMarker core provides are:</p><ul> |
| <li> |
| <p><code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code>: It |
| replaces <code class="inline-code">String</code> with |
| <code class="inline-code">SimpleScalar</code>, <code class="inline-code">Number</code> with |
| <code class="inline-code">SimpleNumber</code>, <code class="inline-code">List</code> and array |
| with <code class="inline-code">SimpleSequence</code>, <code class="inline-code">Map</code> |
| with <code class="inline-code">SimpleHash</code>, <code class="inline-code">Boolean</code> |
| with <code class="inline-code">TemplateBooleanModel.TRUE</code> or |
| <code class="inline-code">TemplateBooleanModel.FALSE</code>, W3C DOM nodes with |
| <code class="inline-code">freemarker.ext.dom.NodeModel</code>. For Jython |
| objects, this wrapper will invoke |
| <code class="inline-code">freemarker.ext.jython.JythonWrapper</code>. For all |
| other objects, it will invoke <a href="pgui_misc_beanwrapper.html"><code>BEANS_WRAPPER</code></a>.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">ObjectWrapper.BEANS_WRAPPER</code>: It can |
| expose java Bean properties and other members of arbitrary objects |
| using Java reflection. At least in FreeMarker 2.3, it is a |
| <code class="inline-code">freemarker.ext.beans.BeansWrapper</code> instance; |
| there is a separated <a href="pgui_misc_beanwrapper.html">chapter |
| about it</a>.</p> |
| </li> |
| </ul><p>For a concrete example, let's see how the |
| <code class="inline-code">Simple<em class="code-color">Xxx</em></code> classes work. |
| <code class="inline-code">SimpleHash</code>, <code class="inline-code">SimpleSequence</code> and |
| <code class="inline-code">SimpleCollection</code> use |
| <code class="inline-code">DEFAULT_WRAPPER</code> to wrap the subvariables (unless |
| you pass in an alternative wrapper in their constructor). So this |
| example demonstrates <code class="inline-code">DEFAULT_WRAPPER</code> in |
| action:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">Map map = new HashMap(); |
| map.put("anotherString", "blah"); |
| map.put("anotherNumber", new Double(3.14)); |
| List list = new ArrayList(); |
| list.add("red"); |
| list.add("green"); |
| list.add("blue"); |
| |
| SimpleHash root = new SimpleHash(); // will use the default wrapper |
| root.put("theString", "wombat"); |
| root.put("theNumber", new Integer(8)); |
| root.put("theMap", map); |
| root.put("theList", list);</pre></div><p>Assuming that root is the data-model root, the resulting |
| data-model is:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-data-model">(root) |
| | |
| +- theString = "wombat" |
| | |
| +- theNumber = 8 |
| | |
| +- theMap |
| | | |
| | +- anotherString = "blah" |
| | | |
| | +- anotherNumber = 3.14 |
| | |
| +- theList |
| | |
| +- (1st) = "red" |
| | |
| +- (2nd) = "green" |
| | |
| +- (3rd) = "blue"</pre></div><p>Note that the <code class="inline-code">Object</code>-s inside |
| <code class="inline-code">theMap</code> and <code class="inline-code">theList</code> are |
| accessible as subvariables too. This is because when you, say, try to |
| access <code class="inline-code">theMap.anotherString</code>, then the |
| <code class="inline-code">SimpleHash</code> (which is used as root hash here) will |
| silently replace the <code class="inline-code">Map</code> |
| (<code class="inline-code">theMap</code>) with a <code class="inline-code">SimpleHash</code> |
| instance that uses the same wrapper as the root hash, so when you try |
| to access the <code class="inline-code">anotherString</code> subvariable of it, it |
| will replace that with a <code class="inline-code">SimpleScalar</code>.</p><p>If you drop an ``arbitrary'' object into the data-model, |
| <code class="inline-code">DEFAULT_WRAPPER</code> will invoke |
| <code class="inline-code">BEANS_WRAPPER</code> to wrap the object:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">SimpleHash root = new SimpleHash(); |
| // expose a "simple" java objects: |
| root.put("theString", "wombat"); |
| // expose an "arbitrary" java objects: |
| root.put("theObject", new TestObject("green mouse", 1200));</pre></div><p>Assuming this is <code class="inline-code">TestObject</code>:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">public class TestObject { |
| private String name; |
| private int price; |
| |
| public TestObject(String name, int price) { |
| this.name = name; |
| this.price = price; |
| } |
| |
| // JavaBean properties |
| // Note that public fields are not visible directly; |
| // you must write a getter method for them. |
| public String getName() {return name;} |
| public int getPrice() {return price;} |
| |
| // A method |
| public double sin(double x) { |
| return Math.sin(x); |
| } |
| }</pre></div><p>The data-model will be:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-data-model">(root) |
| | |
| +- theString = "wombat" |
| | |
| +- theObject |
| | |
| +- name = "green mouse" |
| | |
| +- price = 1200 |
| | |
| +- number sin(number)</pre></div><p>So we can merge it with this template:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-template">${theObject.name} |
| ${theObject.price} |
| ${theObject.sin(123)}</pre></div><p>Which will output:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-output">green mouse |
| 1200 |
| -0,45990349068959124</pre></div><p>You have seen in earlier examples of this manual that we have |
| used <code class="inline-code">java.util.HashMap</code> as root hash, and not |
| <code class="inline-code">SimpleHash</code> or other FreeMarker specific class. It |
| works because |
| <code class="inline-code">Template.process(<em class="code-color">...</em>)</code> |
| automatically wraps the object you give as its data-model argument. It |
| uses the object wrapper dictated by the |
| <code class="inline-code">Configuration</code> level <a href="pgui_config_settings.html">setting</a>, |
| <code class="inline-code">object_wrapper</code> (unless you explicitly specify an |
| <code class="inline-code">ObjectWrapper</code> as its parameter). Thus, in simple |
| FreeMarker application you need not know about |
| <code class="inline-code">TemplateModel</code>-s at all. Note that the root need not |
| be a <code class="inline-code">java.util.Map</code>. It can be anything that is |
| wrapped so that it implements the <code class="inline-code">TemplateHashModel</code> |
| interface.</p><p>The factory default value of the |
| <code class="inline-code">object_wrapper</code> setting is |
| <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code>. If you want to |
| change it to, say, <code class="inline-code">ObjectWrapper.BEANS_WRAPPER</code>, you |
| can configure the FreeMarker engine (before starting to use it from |
| other threads) like this:</p> |
| |
| <div class="code-wrapper"><pre class="code-block code-unspecified">cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);</pre></div><p>Note that you can set any object here that implements interface |
| <code class="inline-code">ObjectWrapper</code>, so you can set your custom |
| implementation as well.</p><p>For <code class="inline-code">TemplateModel</code> implementations that wrap |
| basic Java container types, as <code class="inline-code">java.util.Map</code>-s and |
| <code class="inline-code">java.util.List</code>-s, the convention is that they use |
| the same object wrapper to wrap their subvariables as their parent |
| container does. Technically correctly said, they are instantiated by |
| their parent container (so it has full control over the creation of |
| them), and the parent container create them so they will use the same |
| object wrapper as the parent itself. Thus, if |
| <code class="inline-code">BEANS_WRAPPER</code> is used for the wrapping of the root |
| hash, it will be used for the wrapping of the subvariables (and the |
| subvariables of the subvariables, etc.) as well. This is exactly the |
| same phenomenon as you have seen with |
| <code class="inline-code">theMap.anotherString</code> earlier.</p><div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_datamodel_node.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config.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> |