Data Models that Implement more than one Interface

More than one template model can be implemented at a time for a given class. For instance, a class could have the following signature:

public class MyModel implements TemplateHashModel, TemplateMethodModel,
        TemplateSequenceModel {

    // Implementation goes here...
        
}
        

When presented with a class such as the above, FreeMarker will attempt to "do the right thing". Supposing such a class was placed inside a TemplateModelRoot implementation, under the key name of demo. A FreeMarker template could perform all of the following:

<comment>
The following will index element one of the TemplateListModel 
implementation...
</comment>

The second element of the list is: ${demo[ 1 ]}

<comment>
The following will reference the key name "hello" of the TemplateHashModel 
implementation...
</comment>

Say hello: ${demo.hello}
And again: ${demo[ "hello" ]}

<comment>
The following will call the "demo" method (the TemplateMethodModel
implementation)...
</comment>

Call from the demo() method... ${demo()}
	

Caveats

In the case of dynamic key syntax, if your model implements both TemplateSequenceModel and TemplateHashModel, be aware of the distinction between strings and numbers. mymodel[1] is a completely different thing from mymodel["1"]. In the first case, FreeMarker will interpret mymodel as a TemplateSequenceModel and in the second case, as a TemplateHashModel.

If you use dot notation (eg. foo.bar) to reference keys inside your model, FreeMarker will always treat the key as being a TemplateHashModel.

There is sometimes actually something of an ambiguity in the template language when an object implements more than one of the core interfaces. For example, if a model implements both TemplateScalarModel and TemplateSequenceModel, there is ambiguity as to whether myModel[1..3] says that you should get the second through the fourth element of the list that this represents, or the substring consisting of the second through the fourth characters, when the model is treated as a string. In fact, in this case, the list interpretation takes precedence. There is a trick to get the string. You can write:

("" + myModel)[1..3]
	

The expression (""+myModel) resolves to a "pure" string so that then the interpretation is clear and the entire expression will resolve to the substring, not the sublist.