The object wrapper is an object that implements the
        freemarker.template.ObjectWrapper interface. It's
        purpose is to implement a mapping between Java objects (like
        String-s, Map-s,
        List-s, instances of your application specific
        classes, etc.) and FTL's type system. With other words, it specifies
        how the templates will see the Java objects of the data-model
        (including the return value of Java methods called from the template).
        The object wrapper is plugged into the
        Configuration as its
        object_wrapper setting (or with
        Configuration.setObjectWrapper).
FTL's type system is technically represented by the
        TemplateModel sub-interfaces that were introduced
        earlier (TemplateScalarModel,
        TemplateHashMode,
        TemplateSequenceModel, etc). To map a Java object
        to FTL's type system, object wrapper's TemplateModel
        wrap(java.lang.Object obj) method will be called.
Sometimes FreeMarker needs to reverse this mapping, in which
        case the ObjectWrapper's Object
        unwrap(TemplateModel) method is called (or some other
        variation of that, but see the API documentation for such details).
        This last operation is in
        ObjectWrapperAndUnwrapper, the subinterface of
        ObjectWrapper. Most real world object wrappers will
        implement ObjectWrapperAndUnwrapper.
Here's how wrapping Java objects that contain other objects
        (like a Map, a List, an array,
        or an object with some JavaBean properties) usually work. Let's say,
        an object wrapper wraps an Object[] array into some
        implementation of the TemplateSquenceModel
        interface. When FreeMarker needs an item from that FTL sequence, it
        will call TemplateSquenceModel.get(int index). The
        return type of this method is TemplateModel, that
        is, the TemplateSquenceModel implementation not
        only have to get the Object from the given index of
        the array, it's also responsible for wrapping that value before
        returning it. To solve that, a typical
        TemplateSquenceModel implementation will store the
        ObjectWrapper that has cerated it, and then invoke
        that ObjectWrapper to wrap the contained value. The
        same logic stands for TemplateHashModel or for any
        other TemplateModel that's a container for further
        TemplateModel-s. Hence, usually, no mater how deep
        the value hierarchy is, all values will be wrapped by the same single
        ObjectWrapper. (To create
        TemplateModel implementations that follow this
        idiom, you can use the
        freemarker.template.WrappingTemplateModel as base
        class.)
The data-model itself (the root variable) is a
        TemplateHashModel. The root object that you specify
        to Template.process will be wrapped with the object
        wrapper specified in the object_wrapper
        configuration setting, which must yield a
        TemplateHashModel. From then on, the wrapping of
        the contained values follow the logic described earlier (i.e., the
        container is responsible for wrapping its children).
Well behaving object wrappers bypass objects that already
        implement TemplateModel as is. So if you put an
        object into the data-model that already implements
        TemplateModel (or you return as such object from a
        Java method that's called from the template, etc.), then you can avoid
        actual object wrapping. You do this usually when you are creating a
        value specifically to be accessed from a template. Thus, you avoid
        much of the object wrapping performance overhead, also you can control
        exactly what will the template see (not depending on the mapping
        strategy of the current object wrapper). A frequent application of
        this trick is using a
        freemarker.template.SimpleHash as the data-model
        root (rather than a Map), by filling it with
        SimpleHash's put method (that's
        important, so it won't have to copy an existing Map
        that you have already filled). This speeds up top-level data-model
        variable access.
The default object wrapper
The default of the object_wrapper
          Configuration setting is a
          freemarker.template.DefaultObjectWrapper
          singleton. Unless you have very special requirements, it's
          recommended to use this object wrapper, or an instance of a
          DefaultObjectWrapper subclass of yours.
It recognizes most basic Java types, like
          String, Number,
          Boolean, Date,
          List (and in general all kind of
          java.util.Collection-s), arrays,
          Map, etc., and wraps them into the naturally
          matching TemplateModel interfaces. It will also
          wrap W3C DOM nodes with
          freemarker.ext.dom.NodeModel, so you can
          conveniently traverse XML as described in its
          own chapter). For Jython objects, it will delegate to
          freemarker.ext.jython.JythonWrapper. For all
          other objects, it will invoke BeansWrapper.wrap
          (the super class's method), which will expose the JavaBean
          properties of the objects as hash items (like
          myObj.foo in FTL will call
          getFoo() behind the scenes), and will also expose
          the public methods (JavaBean actions) of the object (like
          myObj.bar(1, 2) in FTL will call a method). (For
          more information about BeansWrapper, see its own section.)
Some further details that's worth mentioning about
          DefaultObjectWrapper:
- 
              
You shouldn't use its constructor usually, instead create it using a
DefaultObjectWrapperBuilder. This allows FreeMarker to use singletons. - 
              
DefaultObjectWrapperhas anincompatibleImprovementsproperty, that's highly recommended to set it to a high value (see the API documentation for the effects). How to set it:- 
                  
If you have set the
incompatible_improvementssetting of theConfigurationto 2.3.22 or higher, and you didn't set theobject_wrappersetting (so it had remained on its default value), then you have to do nothing, as it already uses aDefaultObjectWrappersingleton with the equivalentincompatibleImprovementsproperty value. - 
                  
Otherwise you have to set the
incompatibleImprovementsindependently of theConfiguration. Depending on how you create/set theObjectWrapper, it can be done like this:- 
                      
If you are using the builder API:
... = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27).build()
 - 
                      
Or, if you are using the constructor:
... = new DefaultObjectWrapper(Configuration.VERSION_2_3_27)
 - 
                      
Or, if you are using the
object_wrapperproperty (*.propertiesfile orjava.util.Propertiesobject):object_wrapper=DefaultObjectWrapper(2.3.27)
 - 
                      
Or, if you are configuring the
object_wrapperthrough aFreemarkerServletwith aninit-paraminweb.xml:<init-param> <param-name>object_wrapper</param-name> <param-value>DefaultObjectWrapper(2.3.27)</param-value> </init-param> 
 - 
                      
 
 - 
                  
 - 
              
In new or properly test-covered projects it's also recommended to set the
forceLegacyNonListCollectionsproperty tofalse. If you are using.propertiesorFreemarkerServletinit-params or such, that will look likeDefaultObjectWrapper(2.3.22, forceLegacyNonListCollections=false), while with the Java API you callsetForceLegacyNonListCollections(false)on theDefaultObjectWrapperBuilderobject before callingbuild(). - 
              
The most common way of customizing
DefaultObjectWrapperis overriding itshandleUnknownTypemethod. 
Custom object wrapping example
Let's say you have an application-specific class like this:
package com.example.myapp;
public class Tupple<E1, E2> {
    public Tupple(E1 e1, E2 e2) { ... }
    public E1 getE1() { ... }
    public E2 getE2() { ... }
}    You want templates to see this as a sequence of length 2, so
          that you can do things like someTupple[1],
          <#list someTupple
          ...>, or
          someTupple?size. For that you need to create a
          TemplateSequenceModel implementation that adapts
          a Tupple to the
          TempateSequenceMoldel interface:
package com.example.myapp.freemarker;
...
public class TuppleAdapter extends WrappingTemplateModel implements TemplateSequenceModel,
        AdapterTemplateModel {
    private final Tupple<?, ?> tupple;
    public TuppleAdapter(Tupple<?, ?> tupple, ObjectWrapper ow) {
        super(ow);  // coming from WrappingTemplateModel
        this.tupple = tupple;
    }
    @Override  // coming from TemplateSequenceModel
    public int size() throws TemplateModelException {
        return 2;
    }
    @Override  // coming from TemplateSequenceModel
    public TemplateModel get(int index) throws TemplateModelException {
        switch (index) {
        case 0: return wrap(tupple.getE1());
        case 1: return wrap(tupple.getE2());
        default: return null;
        }
    }
    @Override  // coming from AdapterTemplateModel
    public Object getAdaptedObject(Class hint) {
        return tupple;
    }
}    Regarding the classes and interfaces:
- 
              
TemplateSequenceModel: This is why the template will see this as a sequence - 
              
WrappingTemplateModel: Just a convenience class, used forTemplateModel-s that do object wrapping themselves. That's normally only needed for objects that contain other objects. See thewrap(...)calls above. - 
              
AdapterTemplateModel: Indicates that this template model adapts an already existing object to aTemplateModelinterface, thus unwrapping should give back that original object. 
Lastly, we tell FreeMarker to wrap Tupple-s
          with the TuppleAdapter (alternatively, you could
          wrap them manually before passing them to FreeMarker). For that,
          first we create a custom object wrapper:
package com.example.myapp.freemarker;
...
public class MyAppObjectWrapper extends DefaultObjectWrapper {
    public MyAppObjectWrapper(Version incompatibleImprovements) {
        super(incompatibleImprovements);
    }
    @Override
    protected TemplateModel handleUnknownType(final Object obj) throws TemplateModelException {
        if (obj instanceof Tupple) {
            return new TuppleAdapter((Tupple<?, ?>) obj, this);
        }
        return super.handleUnknownType(obj);
    }
}    and then where you configure FreeMarker (about configuring, see here...) we plug our object wrapper in:
// Where you initialize the cfg *singleton* (happens just once in the application life-cycle): cfg = new Configuration(Configuration.VERSION_2_3_27); ... cfg.setObjectWrapper(new MyAppObjectWrapper(cfg.getIncompatibleImprovements()));
or if you are configuring FreeMarker with
          java.util.Properties instead (and let's say it's
          also a .properties file):
object_wrapper=com.example.myapp.freemarker.MyAppObjectWrapper(2.3.27)
