Seldom used and expert built-ins - FreeMarker Manual

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# Seldom used and expert built-ins

These are the built-ins that normally you should not use, but in exceptional situations (debugging, advanced macros) they can be useful. If you need to use these in your normal page templates, you may revisit the data-model so you don't need to use these.

## api, has_api

Note:

These built-ins exists since FreeMarker 2.3.22

`value?api` provides access to the API (usually, the Java API) of `value`, like `value?api.someJavaMethod()`, if the value itself supports this extra feature. This meant to be used rarely, when you need to call a Java method of an object, but the simplistic view of the value that FreeMarker exposes to the templates hides that, and there's no equivalent built-in either. For example, when you have `Map` that you put into the data-model (and you are using the default object wrapper), `myMap.myMethod()` in a template basically translates to `((Method) myMap.get("myMethod")).invoke(...)` in Java, thus you can't call `myMethod`. If, however, you write `myMap?api.myMethod()` instead, that means `myMap.myMethod()` in Java.

You should avoid using `api`, and rely on the capabilities of the FTL types and the related built-ins as far as possible. For example, don't use `users?api.size()`, but `users?size`. The variation that uses `?api` is more verbose, slower, more easily breaks when FreeMarker configuration settings are changed, and most importantly, more prone to break as the technical details of the data-model changes. For example, if `users` is changed from a `List` to an array, `users?size` will keep working, while `users?api.size()` will break.

Avoid calling methods that modify an object (especially `Map`-s and `Collection`-s) or that aren't thread safe from other reasons. Templates usually aren't expected to modify the objects exposed to them, just to display them. Thus the application may passes some objects to multiple (possibly concurrent) template processings.

The `api` built-in is not everywhere available, some requirements has to be met:

- The `api_builtin_enabled` configuration setting must be set to `true`. Its default is `false` (at least as of 2.3.22) for not lowering the security of existing applications.

- The value itself has to support it. We are talking about the value as the template sees it, which is created from the original object (that's coming from the data-model or from a Java method return value) value via object wrapping. Hence, this depends on the `object_wrapper` FreeMarker configuration setting, and on the class of the wrapped (the original) object:

  - When the object wrapper is a `DefaultObjectWrapper` with its `incompatibleImprovements` set to 2.3.22 or higher (see how to set it here) (actually, what matters is that its `useAdaptersForContainer` property is set to `true`, but that's the default with said `incompatibleImprovements`), FTL values made from `Map`-s and `List`-s support `?api`. Other `java.util.Collections` also, if `DefaultObjectWrapper`'s `forceLegacyNonListCollections` property is set to `false` (default is `true` for better out-of-the-box backward compatibility).

  - When wrapped with pure `BeansWrapper`, all values support `?api`. But again, avoid using it if there's another solution.

  - Custom `TemplateModel`-s can support `?api` by implementing the `freemarker.template.TemplateModelWithAPISupport` interface.

Using `?api` when it's not allowed in the configuration or when the value doesn't support it will abort template processing with error.

Whether a value supports `?api` can be checked like `value?has_api`, which returns a boolean value. Note that the result of `?has_api` isn't influenced by the `api_builtin_enabled` setting.

## byte, double, float, int, long, short

Returns a `SimpleNumber` which contains the same value as the original variable, but uses `java.lang.Type` for the internal representation of the value. This is useful if a method is overloaded, or if a `TemplateModel` unwrapper has problem with automatically choosing the suitable `java.lang.*` type. Note that since version 2.3.9 the unwrapper has been improved substantially, so you will hardly ever need to use these built-ins to convert between numerical types, except for resolving ambiguity in overloaded method invocation.

The `long` built-in can also be used with date, time and date-time values to get the value as `java.util.Date.getTime()` would return. This is useful if you have to call a Java methods that expect a timestamp as a `long`. This conversion is not automatic.

## eval

This built-in evaluates a string as an FTL expression. For example `"1+2"?eval` returns number 3.

The evaluated expression sees the same variables (such as locals) that are visible at the place of the invocation of `eval`. That is, it behaves similarly as if in place of `s?eval` you had the value of `s` there. Except, it can't use loop variable built-ins that refer to a loop variable that was created outside `s`.

The configuration settings that affect the expression parsing (like syntax) are coming from the `Configuration` object, not from template that invokes `eval`.

## has_content

It is `true` if the variable exists (and isn't Java `null`) and is not ``empty'', otherwise it is `false`. The meaning of ``empty'' depends on the concrete case. This follows intuitive common-sense ideas. The following are empty: a string with 0 length, sequence or hash with no sub variables, a collection which has passed the last element. If the value is not a string or sequence or hash or collection, then it counts as non-empty if it's a number or a date or a boolean (e.g. `0` and `false` are not empty), otherwise it counts as empty. Note that when your data-model implements multiple template model interfaces you may get unexpected results. However, when in doubt you can use always use `expr!?size > 0` or `expr!?length > 0` instead of `expr?has_content`.

This buit-in is exceptional in that you can use the parentheses trick like with the default value operator. That is, you can write both `product.color?has_content` and `(product.color)?has_content`. The first doesn't handle the case when `product` is missing, the last does.

## interpret

This built-in parser a string as an FTL template, and returns an user-defined directive that executes that template, just as if a template with that content were `include`-d at that point. Example:

    <#assign x=["a", "b", "c"]>
    <#assign templateSource = r"<#list x as y>${y}</#list>">
    <#-- Note: That r was needed so that the ${y} is not interpreted above -->
    <#assign inlineTemplate = templateSource?interpret>
    <@inlineTemplate />

The output:

    abc

As you can see, `inlineTemplate` is a user-defined directive that, when executed, runs the template whose content is the value of `templateSource`.

The configuration settings that affect the parsing (like tag syntax and naming convention) are coming from the `Configuration` object, not from template that calls `interpret`. This also means that the previously auto-detected tag syntax or auto-detected naming convention don't effect the parsing of the interpreted template. This is consistent with how the `include` directive works.

The name of the template created by `interpret` is the name of the template that calls `interpret`, plus `"->anonymous_interpreted"`. For example, if the template that calls the built-in is `"foo/bar.ftl"`, then the name of the resulting template is `"foo/bar.ftl->anonymous_interpreted"`. Thus, relative paths inside the interpreted template are relative to this path (i.e., the base directory will be `"foo"`), and errors inside the interpreted template will point to this generated template name.

For more helpful error messages, you can override the template name part after the `"->"`. For example, let's say `mailTemplateSource` comes from the `mail_template` database table, and in the case of error, you want the error log to contain the database ID of the failing template:

    <#assign inlineTemplate = [mailTemplateSource, "mail_templates id=${mailTemplateId}"]?interpret>

As you can see, `interpret` can be applied on a sequence of two items, in which case the first item is the FTL string to interpret, and the second items is the template name used after the `"->"`.

## is_...

These built-ins check the type of a variable, and returns `true` or `false` depending on the type. The list of `is_...` built-ins:

Built-in | Returns `true` if the value is a ...
--- | ---
`is_string` | string
`is_number` | number
`is_boolean` | boolean
`is_date` | Don't use it! Same as `is_date_like`, use that instead. Later may changes meaning to `date_only`.
`is_date_like` | date-like, means either date, time or date-time, or date-like with unknown precise type (since FreeMarker 2.3.21)
`is_date_only` | date (no time of the day part) (since FreeMarker 2.3.21)
`is_time` | time (no year-month-day part) (since FreeMarker 2.3.21)
`is_datetime` | date-time (contains both year-month-day and time of the day)
`is_unknown_date_like` | date-like where we don't know if it's a date or a time or a date-time
`is_method` | method
`is_transform` | transform
`is_macro` | macro or function (yes, also for function; a historical glitch)
`is_hash` | hash (including extended hash)
`is_hash_ex` | extended hash (supports `?keys` and `?values`)
`is_sequence` | sequence
`is_collection` | collection (including extended collection)
`is_collection_ex` | extended collection (supports `?size`)
`is_enumerable` | sequence or collection
`is_indexable` | sequence
`is_directive` | Whatever kind of directive (for example a macro, or `TemplateDirectiveModel`, `TemplateTransformModel`, etc.), or function (a historical glitch)
`is_node` | node

## namespace

This built-in returns the namespace (i.e. the ``gate'' hash to the namespace) associated with a macro or function variable. You can use it with macros and functions only.

## new

This is to create a variable of a certain `TemplateModel` implementation.

On the left side of `?` you specify a string, the full-qualified class name of a `TemplateModel` implementation. The result is a method variable that calls the constructor, and returns the new variable.

Example:

    <#-- Creates an user-defined directive be calling the parameterless constructor of the class -->
    <#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()>
    <#-- Creates an user-defined directive be calling the constructor with one numerical argument -->
    <#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)>

For more information about how the constructor parameters are unwrapped and how overloaded constructor is chosen, read: Programmer's Guide/Miscellaneous/Bean wrapper

This built-in can be a security concern because the template author can create arbitrary Java objects and then use them, as far as they implement `TemplateModel`. Also the template author can trigger static initialization for classes that don't even implement `TemplateModel`. You can (since 2.3.17) restrict the classes accessible with this built-in using `Configuration.setNewBuiltinClassResolver(TemplateClassResolver)` or the `new_builtin_class_resolver` setting. See the Java API docs for more information. If you are allowing not-so-much-trusted users to upload templates then you should definitely look into this topic.

## number_to_date, number_to_time, number_to_datetime

These are used to convert a number (usually a Java `long`) to a date, time or date-time, respectively. This does them same as `new java.util.Date(long)` in Java, that is, the number is interpreted as the milliseconds passed since the epoch. The number can be anything and of any type as far as its value fits into a `long`. If the number isn't a whole number, it will be rounded to whole with half-up rule. This conversion is not automatic.

Example:

    ${1305575275540?number_to_datetime}
    ${1305575275540?number_to_date}
    ${1305575275540?number_to_time}

The output will be something like this (depending on the current locale and time zone):

    May 16, 2011 3:47:55 PM
    May 16, 2011
    3:47:55 PM

Previous Next