Expressions - Apache FreeMarker Manual
Unsupported web browser - Use a modern browser to view this website!
Manual
Java API
Contribute
Report a Bug
Manual
Apache FreeMarker Manual
Template Author's Guide
The Template
Expressions
Bookmarks:
Alpha. index
Glossary
Expressions
?builtins
#directives
.spec_vars
FAQ
Previous
Next
Expressions
Page Contents
Quick overview (cheat sheet)
Specify values directly
Strings
Numbers
Booleans
Sequences
Ranges
Hashes
Retrieving variables
Top-level variables
Retrieving data from a hash
Retrieving data from a sequence
Special variables
String operations
Interpolation and concatenation
Getting a character
String slicing (substrings)
Sequence operations
Concatenation
Sequence slicing
Hash operations
Concatenation
Arithmetical calculations
Comparison
Logical operations
Built-ins
Method call
Handling missing values
Default value operator
Missing value test operator
Assignment Operators
Local lambdas
Parentheses
White-space in expressions
Comments in expressions
Operator precedence
When you supply values for interpolations or directive
parameters you can use variables or more complex expressions. For
example, if x is the number 8 and y is 5, the value of
(x +
y)/2
resolves to the numerical value 6.5.
Before we go into details, let's see some concrete
examples:
When you supply value for interpolations: The usage of
interpolations is
${
expression
where
expression gives the value you want to insert into the output as
text. So
${(5 + 8)/2}
prints "6.5"
to the output (or possibly "6,5" if the language of
your output is not US English).
When you supply a value for the directive parameter: You
have already seen the
if
directive in the
Getting Started section. The syntax of this directive is:
<#if
expression
...
#if>
The expression here must evaluate to a boolean value. For example
in
<#if 2 < 3>
the
2 <
(2 is less than 3) is an expression which evaluates to
true
Quick overview (cheat sheet)
This is a reminder for those of you who already know
FreeMarker or are just experienced programmers:
Specify values
directly
Strings
"Foo"
or
'Foo'
or
"It's \"quoted\""
or
'It\'s
"quoted"'
or
r"C:\raw\string"
Numbers
123.45
Booleans
true
false
Sequences
["foo", "bar", 123.45]
; Ranges:
0..9
0..<10
(or
0..!10
),
0..
Hashes
{"name":"green mouse",
"price":150}
Retrieving
variables
Top-level
variables
user
Retrieving
data from a hash
user.name
user["name"]
Retrieving data
from a sequence
products[5]
Special
variable
.main
String
operations
Interpolation
and concatenation
"Hello ${user}!"
(or
"Hello
" + user + "!"
Getting a
character
name[0]
String
slice:
Inclusive end:
name[0..4]
Exclusive end:
name[0..<5]
Length-based (lenient):
name[0..*5]
Remove starting:
name[5..]
Sequence
operations
Concatenation
users + ["guest"]
Sequence
slice
: Inclusive end:
products[20..29]
, Exclusive end:
products[20..<30]
, Length-based
(lenient):
products[20..*10]
, Remove
starting:
products[20..]
Hash
operations
Concatenation
passwords + { "joe": "secret42" }
Arithmetical
calculations
(x * 1.5 + 10) / 2 - y %
100
Comparison
x == y
x != y
x < y
x > y
x >= y
x <= y
x lt y
x lte y
x gt y
x gte y
...etc.
Logical
operations
!registered && (firstVisit
|| fromEurope)
Built-ins
name?upper_case
path?ensure_starts_with('/')
Method
call
repeat("What", 3)
Missing value
handler operators
Default
value
name!"unknown"
or
(user.name)!"unknown"
or
name!
or
(user.name)!
Missing
value test
name??
or
(user.name)??
Assignment
operators
+=
-=
*=
/=
%=
++
--
Local
lambdas
x -> x + 1
(x,
y) -> x + y
See also:
Operator
precedence
Specify values directly
Often you want to specify a value directly and not as a result
of some calculations.
Strings
To specify a string value directly you give the text in
quotation marks, e.g.:
"some text"
or in
apostrophe-quote, e.g.
'some text'
. The two
forms are equivalent. If the text itself contains the character
used for the quoting (either
or
) or backslashes, you have to precede them
with a backslash; this is called escaping. You can type any other
character, including
line
breaks
, in the text directly. Example:
Template
${"It's \"quoted\" and
this is a backslash: \\"}
${'It\'s "quoted" and
this is a backslash: \\'}
will print:
Output
It's "quoted" and
this is a backslash: \
It's "quoted" and
this is a backslash: \
Note:
Of course, you could simply type the above text into the
template, without using
${
...
. But we do
it here just for the sake of example, to demonstrate
expressions.
This is the list of all supported escape sequences. All
other usage of backlash in string literals is an error and any
attempt to use the template will fail.
Escape sequence
Meaning
\"
Quotation mark (u0022)
\'
Apostrophe (a.k.a. apostrophe-quote) (u0027)
\{
Opening curly brace:
\=
Equals character:
(Supported since
FreeMarker 2.3.28.)
\\
Back slash (u005C)
\n
Line feed (u000A)
\r
Carriage return (u000D)
\t
Horizontal tabulation (a.k.a. tab) (u0009)
\b
Backspace (u0008)
\f
Form feed (u000C)
\l
Less-than sign:
\g
Greater-than sign:
\a
Ampersand:
\x
Code
Character given with its hexadecimal
Unicode
code (
UCS
code)
The
Code
after
the
\x
is 1 to 4 hexadecimal digits. For
example this all put a copyright sign into the string:
"\xA9 1999-2001"
"\x0A9 1999-2001"
"\x00A9 1999-2001"
. When the character directly
after the last hexadecimal digit can be interpreted as hexadecimal
digit, you must use all 4 digits or else FreeMarker will
misunderstand you.
Note that the character sequence
${
and
#{
(and rarely
[=
instead,
depending on
the
configured syntax
) has special meaning. They are used to
insert the value of expressions (typically: the value of
variables, as in
"Hello ${user}!"
). This will
be explained
later
If you want to print
${
or
#{
(or
[=
), you should
either use raw string literals as explained below, or escape the
like in
"foo $\{bar}"
(or
the
like in
"foo
[\=bar]"
).
A special kind of string literals is the raw string
literals. In raw string literals, backslash and
${
have no special meaning, they are considered
as plain characters. To indicate that a string literal is a raw
string literal, you have to put an
directly
before the opening quotation mark or apostrophe-quote.
Example:
Template
${r"${foo}"}
${r"C:\foo\bar"}
will print:
Output
${foo}
C:\foo\bar
Numbers
To specify a numerical value directly you type the number
without quotation marks. You have to use the dot as your decimal
separator and must not use any grouping separator symbols. You can
use
or
to indicate the
sign (
is redundant). Scientific notation is
not yet supported (so
1E3
is wrong). Also, you
cannot omit the 0 before the decimal separator (so
.5
is wrong).
Examples of valid number literals:
0.08
-5.013
008
11
+11
Note that numerical literals like
08
+8
8.00
and
are totally equivalent as they all symbolize
the number eight. Thus,
${08}
${+8}
${8.00}
and
${8}
will all print exactly same.
Booleans
To specify a boolean value you write
true
or
false
. Don't use quotation marks.
Sequences
To specify a literal sequence, you list the
sub variables
separated by
commas, and put the whole list into square brackets. For
example:
Template
<#list
["foo", "bar", "baz"]
as x>
${x}
#list>
will print:
Output
foo
bar
baz
The items in the list are expressions, so you can do this
for example:
[2 + 2, [1, 2, 3, 4], "foo"]
. Here
the first subvariable will be the number 4, the second will be
another sequence, and the third subvariable will be the string
"foo".
Ranges
Ranges are just sequences, but they are created by
specifying what range of whole numbers they contain, instead of
specifying their items one by one. For example,
0..
variable stores 5, will give a sequence that contains
[0,
1, 2, 3, 4]
. Ranges are primarily used for iterating
over a range of numbers with
<#list
...
and for
slicing
sequences
and
slicing
strings
The generic forms of range expressions are (where
start
and
end
can be any
expression that evaluates to a number):
start
..
end
Range with inclusive end. For example,
1..4
gives
[1, 2, 3, 4]
, and
4..1
gives
[4, 3, 2, 1]
Beware, ranges with inclusive end never give an empty
sequence, so
0..length-1
is
WRONG
, because when length is
it gives
[0,
-1]
start
..<
end
or
start
..!
end
Range with exclusive end. For example,
1..<4
gives
[1, 2,
3]
4..<1
gives
[4,
3, 2]
, and
1..<1
gives
[]
. Note the last example; the result can
be an empty sequence. There's no difference between
..<
and
..!
; the last
form is used in applications where using the
character causes problems (for HTML
editors and such).
start
..*
length
Length limited range. For example,
10..*4
gives
[10, 11, 12, 13]
10..*-4
gives
[10, 9, 8,
7]
, and
10..*0
gives
[]
. When these kind of ranges are used for
slicing, the slice will end without error if the end of the
sliced sequence or string is reached before the specified
range length was reached; see
slicing
sequences
for more.
Note:
Length limited ranges were introduced in FreeMarker
2.3.21.
start
..
Right-unbounded range. This are like length limited ranges
with infinite length. For example
1..
gives
[1, 2, 3, 4, 5, 6, ... ]
, up to infinity.
Be careful when processing (like listing) such ranges, as
processing all items of it it would take forever or until the
application runs out of memory and crashes. Just like with
length limited ranges, when these kind of ranges are used for
slicing, the slice will end when the end of the sliced
sequence or string is reached.
Warning!
Right-unbounded ranges before FreeMarker 2.3.21 were
only used for slicing, and behaved like an empty sequence
for other purposes. To activate the new behavior, it's not
enough to use FreeMarker 2.3.21, the programmer also have to
set the
incompatible_improvements
configuration setting to at least 2.3.21.
Further notes on ranges:
Range expressions themselves don't have square brackets,
for example, you write
<#assign myRange =
0..
<#assign myRange =
[0..
. The last would create a sequence
that contains an item that's a range. The square brackets are
part of the slicing syntax, like
seq
myRange
You can write arithmetical expression on the sides of
the
..
without parenthesis, like
+ 1 ..< m / 2 - 1
..
..<
..!
and
..*
are
operators, so you can't have space inside them. Like
n ..
n ..<
is good.
The reported size of right-unbounded ranges is
2147483647 (or 0 if
incompatible_improvements
is less than
2.3.21) due to a technical limitation (32 bits). However, when
listing them, their actual size is infinite.
Ranges don't really store the numbers they consist of,
thus for example
0..1
and
0..100000000
is equally fast to create and
takes the same amount of memory.
Hashes
To specify a hash in a template, you list the key/value
pairs separated by commas, and put the list into curly brackets.
The key and value within a key/value pair are separated with a
colon. Here is an example:
{ "name": "green mouse",
"price": 150 }
. Note that both the names and the values
are expressions. The keys must be strings. The values can be if
any type.
Retrieving variables
Top-level variables
To access a top-level variable, you simply use the variable
name. For example, the expression
user
will
evaluate to the value of variable stored with name
"user" in the root. So this will print what you store
there:
Template
${user}
If there is no such top-level variable, then an error will
result when FreeMarker tries to evaluate the expression, and it
aborts template processing (unless programmers has configured
FreeMarker differently).
In this kind of expression, the variable name can only
contain letters (including non-Latin letters), digits (including
non-Latin digits), underline (
), dollar
), at sign (
).
Furthermore, the first character can't be an ASCII digit
). Since FreeMarker
2.3.22 the variable name can also contain minus
), dot (
), and colon
) at any position, but these must be escaped
with a preceding backslash (
), otherwise they
are interpreted as operators. For example, to read the variable
whose name is "data-id", the expression is
data\-id
, as
data-id
would
be interpreted as "data minus id". (Note that these
escapes only work in identifiers, not in string literals.)
Furthermore, since FreeMarker 2.3.31, hash mark
) can also be used, but must be escaped with
a preceding backslash (
).
Retrieving data from a hash
If we already have a hash as a result of an expression, then
we can get its subvariable with a dot and the name of the
subvariable. Assume that we have this data-model:
Data Model
(root)
+- book
| |
| +- title = "Breeding green mouses"
| |
| +- author
| |
| +- name = "Julia Smith"
| |
| +- info = "Biologist, 1923-1985, Canada"
+- test = "title"
Now we can read the
title
with
book.title
, since the book expression will
return a hash (as explained in the last chapter). Applying this
logic further, we can read the name of the author with this
expression:
book.author.name
There is an alternative syntax if we want to specify the
subvariable name with an expression:
book["title"]
. In the square brackets you can
give any expression as long as it evaluates to a string. So with
this data-model you can also read the title with
book[test]
. More examples; these are all
equivalent:
book.author.name
book["author"].name
book.author["name"]
book["author"]["name"]
When you use the dot syntax, the same restrictions apply
regarding the variable name as with top-level variables (name can
contain only letters, digits,
but can't start with
, also starting from
2.3.22 you can also use
\-
\.
and
\:
). There are no
such restrictions when you use the square bracket syntax, since
the name is the result of an arbitrary expression. (Note, that to
help the FreeMarker XML support, if the subvariable name is
(asterisk) or
**
, then you
do not have to use square bracket syntax.)
As with the top-level variables, trying to access a
non-existent subvariable causes an error and aborts the processing
of the template (unless programmers has configured FreeMarker
differently).
Retrieving data from a sequence
This is the same as for hashes, but you can use the square
bracket syntax only, and the expression in the brackets must
evaluate to a number, not a string. For example to get the name of
the first animal of the
example data-model
(remember
that the number of the first item is 0, not 1):
animals[0].name
Special variables
Special variables are variables defined by the FreeMarker
engine itself. To access them, you use the
variable_name
syntax.
Normally you don't need to use special variables. They are
for expert users. The complete list of special variables can be
found in the
reference
String operations
Interpolation and concatenation
If you want to insert the value of an expression into a
string, you can use
${
...
(and the
deprecated
#{
...
in string literals.
${
...
in string
literals
behaves
similarly as in
text
sections
(so it goes through the same
locale
sensitive
number and date/time formatting).
Note:
It's possible to configure FreeMarker's interpolation
syntax to use
[=
...
instead;
see
here
Example (assume that user is "Big Joe"):
Template
<#assign s = "Hello ${user}!">
${s} <#-- Just to see what the value of s is -->
This will print:
Output
Hello Big Joe!
Warning!
A frequent mistake of users is the usage of interpolations
in places where they needn't/shouldn't/can't be used.
Interpolations work
only
in
text
sections
(e.g.Hello ${name}!
) and in
string literals (e.g.
<#include
"/footer/${company}.html">
). A typical
WRONG
usage is
<#if
${big}>...#if>
, which will cause a
syntactical error. You should simply write
<#if
big>...#if>
. Also,
<#if
"${big}">...#if>
is
WRONG
, since it converts the parameter
value to string and the
if
directive wants a
boolean value, so it will cause a runtime error.
Alternatively,
you can use the
operator to achieve similar
result:
Template
<#assign s = "Hello " + user + "!">
This gives the same result as the earlier example with the
${
...
Warning!
Because
follows similar rules as
${
...
, the
appended string is influenced by the
locale
number_format
date_format
time_format
datetime_format
and
boolean_format
, etc. settings, and thus the
result targets humans and isn't in generally machine parseable.
This mostly leads to problems with numbers, as many locales use
grouping (thousands separators) by default, and so
"someUrl?id=" + id
becomes to something like
"someUrl?id=1 234"
. To prevent this, use the
?c
(for Computer audience) built-in, like in
"someUrl?id=" + id?c
or
"someUrl?id=${id?c}"
, which will evaluate to
something like
"someUrl?id=1234"
, regardless
of locale and format settings.
As when
${
...
is used inside string
expressions
it's just a
shorthand of using the
operator,
auto-escaping
is not
applied on it.
Getting a character
You can get a single character of a string at a given index
similarly as you can
read the subvariable of a
sequence
, e.g.
user[0]
. The result will
be a string whose length is 1; FTL doesn't have a separate
character type. As with sequence sub variables, the index must be
a number that is at least 0 and less than the length of the
string, or else an error will abort the template
processing.
Since the sequence subvariable syntax and the character
getter syntax clashes, you can use the character getter syntax
only if the variable is not a sequence as well (which is possible
because FTL supports multi-typed values), since in that case the
sequence behavior prevails. (To work this around, you can use
the
string
built-in
, e.g.
user?string[0]
. Don't worry if you don't
understand this yet; built-ins will be discussed later.)
Example (assume that user is "Big Joe"):
Template
${user[0]}
${user[4]}
will print (note that the index of the first character is
0):
Output
String slicing (substrings)
You can slice a string in the same way as you
slice a
sequence
(see there), only here instead of sequence items
you work with characters. Some differences are:
Decreasing ranges aren't allowed for string slicing.
(That's because unlike sequences, you seldom if ever want to
show a string reversed, so if that happens, that's almost
always the result of an oversight.)
If a value is both a string and a sequence (a
multi-typed value), then slicing will slice the sequence
instead of the string. When you are processing XML, such
values are common. In such cases you can use
someXMLnode
?string[
range
to fore string slicing.
There's a legacy bug where a range with
inclusive
end that's one less than the
starting index and is non-negative (like in
"abc"[1..0]
) will give an empty string
instead of an error. (It should be an error as it's a
decreasing range.) Currently this bug is emulated for backward
compatibility, but you shouldn't utilize it, as in the future
it will be certainly an error.
Example:
Template
<#assign s = "ABCDEF">
${s[2..3]}
${s[2..<4]}
${s[2..*3]}
${s[2..*100]}
${s[2..]}
will print:
Output
CD
CD
CDE
CDEF
CDEF
Note:
Some of the typical use-cases of string slicing is covered
by convenient built-ins:
remove_beginning
remove_ending
keep_before
keep_after
keep_before_last
keep_after_last
Sequence operations
Concatenation
You can concatenate sequences in the same way as strings,
with
. Example:
Template
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
#list>
will print:
Output
- Joe
- Fred
- Julia
- Kate
Note that sequence concatenation is not to be used for many
repeated concatenations, like for appending items to a sequence
inside a loop. It's just for things like
<#list users
+ admins as person>
. Although concatenating sequences
is fast and is constant time (it's speed is independently of the
size of the concatenated sequences), the resulting sequence will
be always a little bit slower to read than the original two
sequences were. Thus, after tens or hundreds of repeated
concatenations the result can be impractically slow to
reader.
Sequence slicing
With
seq
range
were
range
is a
range value
as
described here
, you can take a slice of the sequence. The
resulting sequence will contain the items from the original
sequence (
seq
) whose
indexes are in the range. For example:
Template
<#assign seq = ["A", "B", "C", "D", "E"]>
<#list seq[1..3] as i>${i}#list>
will print
Output
BCD
Furthermore, the items in the slice will be in the same
order as in the range. Thus for example the above example with the
3..1
range would print
DCB
The numbers in the range must be valid indexes in the
sequence, or else the processing of the template will be aborted
with error. Like in the last example,
seq[-1..0]
would be an error as
seq[-1]
is invalid, also
seq[1..5]
would be because
seq[5]
is invalid. (Note that
seq[100..<100]
or
seq[100..*0]
would be valid despite that 100 is
out of bounds, because those ranges are empty.)
Length limited ranges
start
..*
length
and right-unbounded ranges
start
..
) adapt to
the length of the sliced sequence. They will slice out at most as
many items as there is available:
Template
<#assign seq = ["A", "B", "C"]>
Slicing with length limited ranges:
- <#list seq[0..*2] as i>${i}#list>
- <#list seq[1..*2] as i>${i}#list>
- <#list seq[2..*2] as i>${i}#list> <#-- Not an error -->
- <#list seq[3..*2] as i>${i}#list> <#-- Not an error -->
Slicing with right-unlimited ranges:
- <#list seq[0..] as i>${i}#list>
- <#list seq[1..] as i>${i}#list>
- <#list seq[2..] as i>${i}#list>
- <#list seq[3..] as i>${i}#list>
This will print:
Output
Slicing with length limited ranges:
- AB
- BC
- C
Slicing with right-unlimited ranges:
- ABC
- BC
- C
Note above that slicing with length limited and right
unbounded ranges allow the starting index to be past the last item
by one
(but no more).
Note:
To split a sequence to slices of a given size, you should
use the
chunk
built-in.
Hash operations
Concatenation
You can concatenate hashes in the same way as strings, with
. If both hashes contain the same key, the
hash on the right-hand side of the
takes
precedence. Example:
Template
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
will print:
Output
- Joe is 30
- Fred is 25
- Julia is 18
Note that hash concatenation is not to be used for many
repeated concatenations, like for adding items to a hash inside a
loop. While adding together hashes is fast and is constant time
(independent of the size of the hashes added), the resulting hash
is a bit slower to read than the hashes added together. Thus after
tens or hundreds of additions the result can be impractically slow
to read.
Arithmetical calculations
This is the basic 4-function calculator arithmetic plus the
modulus operator. So the operators are:
Addition:
Subtraction:
Multiplication:
Division:
Modulus (remainder) of integer operands:
Example:
Template
${100 - x * x}
${x / 2}
${12 % 10}
Assuming that
is 5, it will print:
Output
75
2.5
Both operands must be expressions which evaluate to a
numerical value. So the example below will cause an error when
FreeMarker tries to evaluate it, since
"5"
is a
string and not the number 5:
Template
${3 * "5"} <#-- WRONG! -->
There is an exception to the above rule. The
operator, is used to
concatenate
strings
as well. If on one side of
is a
string and on the other side of
is a numerical
value, then it will convert the numerical value to string (using the
format appropriate for language of the page) and then use the
as string concatenation operator.
Example:
Template
${3 + "5"}
Output
35
Generally, FreeMarker never converts a string to a number
automatically, but it may convert a number to a string
automatically.
People often want only the integer part of the result
of a division (or of other calculations). This is possible with the
int
built-in. (Built-ins are explained
later
):
Template
${(x/2)?int}
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}
Assuming that
is 5, it will print:
Output
-1
-1
Due to historical reasons, the
operator
works by first truncating the operands to an integer number, and
then returning the remainder of the division:
Template
${12 % 5} <#-- Prints 2 -->
${12.9 % 5} <#-- Prints 2 -->
${12.1 % 5} <#-- Prints 2 -->
${12 % 6} <#-- Prints 0 -->
${12 % 6.9} <#-- Prints 0 -->
The sign of the result of
is the same as
the sign of the left hand operand, and its absolute value is the
same as if both operands where positive:
Template
${-12 % -5} <#-- Prints -2 -->
${-12 % 5} <#-- Prints -2 -->
${12 % -5} <#-- Prints 2 -->
About the precision of the operations:
By default FreeMarker uses
BigDecimal
-s for all
arithmetical calculations, to avoid rounding and overflow/underflow
artifacts, and also keeps the result as
BigDecimal
-s. So
(addition),
(subtraction) and
(multiplication) are "lossless". Again by default,
(division) results are calculated to 12
decimals with half-up rounding (unless some operands have even more
decimals, in which case it's calculated with that much decimals).
All this behavior depends on the
arithmetic_engine
configuration setting
Configurable.setArithmericEngine(ArithmericEngine)
though, and some application might use a different value than the
default, although that's highly uncommon.
Comparison
Sometimes you want to know if two values are equal or not, or
which value is the greater.
To show concrete examples I will use the
if
directive here. The usage of
if
directive is:
<#if
expression
>...#if>
where expression must evaluate to a boolean value or else an error
will abort the processing of the template. If the value of
expression is
true
then the things between the
begin and end-tag will be processed, otherwise they will be
skipped.
To test two values for equality you use
==
(or
as a
deprecated
alternative) To test two values for inequality you use
!=
. For example, assume that
user
is "Big Joe":
Template
<#if
user == "Big Joe"
It is Big Joe
#if>
<#if
user != "Big Joe"
It is not Big Joe
#if>
The
user == "Big Joe"
expression in the
<#if ...>
will evaluate to the boolean
true
, so the above will say "It is Big
Joe".
The expressions on both sides of the
==
or
!=
must evaluate to a scalar (not a sequence or
hash). Furthermore, the two scalars must have the same type (i.e.
strings can only be compared to strings and numbers can only be
compared to numbers, etc.) or else an error will abort template
processing. For example
<#if 1 == "1">
will
cause an error. Note that FreeMarker does exact comparison, so
string comparisons are case and white-space sensitive:
"x"
and
"x "
and
"X"
are not equal values.
For numerical and date, time and date-time values you can also
use
<=
>=
and
. You can't use
them for strings! Example:
Template
<#if x
<=
12>
x is less or equivalent with 12
#if>
There's a problem with
>=
and
. FreeMarker interprets the
character as the closing character of the
FTL tag. To prevent this, you can use
lt
instead
of
lte
instead of
<=
gt
instead of
and
gte
instead of
>=
, like in
<#if x gt
y>
. Another trick it to put the expression into
parentheses
like in
<#if (x > y)>
, although it's considered
to be less elegant.
FreeMarker supports some more syntactical alternatives:
>
and
<
can also be used, like in:
<#if x > y>
or
<#if
x >= y>
. This isn't meant to be entered
manually; it's to work around cases where the template gets
XML/HTML escaped and the user can't easily prevent that
happening. Note that in general FTL does not support entity
references (the
...
things)
in FTL tags; it's just an exception with these operators.
Deprecated forms:
\lt
\lte
\gt
and
\gte
. These are the same as the ones without
the backslash.
Logical operations
Just the usual logical operators:
Logical or:
||
Logical and:
&&
Logical not:
The operators will work with boolean values only. Otherwise an
error will abort the template processing.
Example:
Template
<#if x < 12
&&
color == "green">
We have less than 12 things, and they are green.
#if>
<#if
hot> <#-- here hot must be a boolean -->
It's not hot.
#if>
FreeMarker supports some more syntactical alternatives:
\and
(since FreeMarker 2.3.27): In some
applications using
&&
causes problems
as it's not valid in XML or HTML. While FreeMarker templates was
never intended to be valid XML/HTML, only their output should be
that, in reality there are some applications that expect the
template itself to be valid XML/HTML regardless. This syntax is
a workaround for such cases. Also note that unlike with the
comparison operators,
and
without
is not supported due to backward
compatibility restrictions.
&&
(since FreeMarker
2.3.27): This isn't meant to be entered manually; it's to work
around cases where the template gets XML/HTML escaped and the
user can't easily prevent that happening. Note that in general
FTL does not support entity references (the
...
things)
in FTL tags; it's just an exception with these operators.
Deprecated forms:
and
. Don't use them anymore.
Built-ins
Built-ins are like methods that are added to the objects by
FreeMarker. To prevent name clashes with actual methods and other
sub-variables, instead of dot (
), you separate
them from the parent object with question mark
). For example, if you want to ensure that
path
has an initial
then you
could write
path?ensure_starts_with('/')
. The
Java object behind
path
(a
String
most certainly) doesn't have such method,
FreeMarker adds it. For brevity, if the method has no parameters,
you
must
omit the
()
, like,
to get the length of
path
, you have to write
path?length
not
path?length()
The other reason why built-ins are crucial is that normally
(though it depends on configuration settings), FreeMarker doesn't
expose the Java API of the objects. So despite that Java's
String
has a
length()
method,
it's hidden from the template, you
have to
use
path?length
instead. The advantage of that is
that thus the template doesn't depend on the exactly type of the
underlying Java objects. (Like
path
is maybe a
java.nio.Path
behind the scenes, but if the
programmers has configure FreeMarker to expose
Path
objects as FTL strings, the template won't
be aware of that, and
?length
will work, despite
that
java.nio.Path
has no similar method.)
You can find some of the
most commonly used built-ins
mentioned here
, and the
complete
list of built-ins in the Reference
. For now, just a few of
the more important ones:
Example:
Template
${testString?upper_case}
${testString?html}
${testString?upper_case?html}
${testSequence?size}
${testSequence?join(", ")}
Assuming that
testString
stores the string
"Tom & Jerry", and testSequnce stores the strings
"foo", "bar" and "baz", the
output will be:
Output
TOM & JERRY
Tom & Jerry
TOM & JERRY
foo, bar, baz
Note the
test?upper_case?html
above. Since
the result of
test?upper_case
is a string, you
can apply the
html
built-in on it.
Naturally, the left side of the built-in can be arbitrary
expression, not just a variable name:
Template
${testSeqence[1]?cap_first}
${"horse"?cap_first}
${(testString + " & Duck")?html}
Output
Bar
Horse
Tom & Jerry & Duck
Method call
If you have a method then you can use the method call
operation on it. The method call operation is a comma-separated list
of expressions in parentheses. These values are called parameters.
The method call operation passes these values to the method which
will in turn return a result. This result will be the value of the
whole method call expression.
For example, assume the programmers have made available a
method variable called
repeat
. You give a string
as the first parameter, and a number as the second parameter, and it
returns a string which repeats the first parameter the number of
times specified by the second parameter.
Template
${repeat("Foo", 3)}
will print:
Output
FooFooFoo
Here
repeat
was evaluated to the method
variable (according to how you
access top-level
variables
) and then
("What", 3)
invoked
that method.
I would like to emphasize that method calls are just plain
expressions, like everything else. So this:
Template
${repeat(repeat("x", 2), 3) + repeat("Foo", 4)?upper_case}
will print this:
Output
xxxxxxFOOFOOFOOFOO
Handling missing values
Note:
These operators exist since FreeMarker 2.3.7 (replacing the
default
exists
and
if_exists
built-ins).
As we explained earlier, an error will occur and abort the
template processing if you try to access a missing variable. However
two special operators can suppress this error, and handle the
problematic situation. The handled variable can be top-level
variable, hash subvariable, or sequence subvariable as well.
Furthermore these operators handle the situation when a method call
doesn't return a value
(from the
viewpoint of Java programmers: it returns
null
or
it's return type is
void
, so it's more
correct to say that these operators handle missing values in
general, rather than just missing variables.
For those who know what's Java
null
, FreeMarker 2.3.
treats them as missing values. Simply, the template language doesn't
know the concept of
null
. For example, if you
have a bean that has a
maidenName
property, and
the value of that property is
null
, then that's
the same as if there were no such property at all, as far as the
template is concerned (assuming you didn't configured FreeMarker to
use some extreme object wrapper, that is). The result of a method
call that returns
null
is also treated as a
missing variable (again, assuming that you use some usual object
wrapper). See more
in the
FAQ
Note:
If you wonder why is FreeMarker so picky about missing
variables,
read this
FAQ entry
Default value operator
Synopsis:
unsafe_expr
default_expr
or
unsafe_expr
or
unsafe_expr
)!
default_expr
or
unsafe_expr
)!
This operator allows you to specify a default value for the
case when the value is missing.
Example. Assume no variable called
mouse
is present:
Template
${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}
The output will be:
Output
No mouse.
Jerry
The default value can be any kind of expression, so it
doesn't have to be a string. For example you can write
hits!0
or
colors!["red", "green",
"blue"]
. There is no restriction regarding the
complexity of the expression that specifies the default value, for
example you can write:
cargo.weight!(item.weight *
itemCount + 10)
Warning!
If you have a composite expression after the
, like
1 + x
always
use parentheses, like
${x!(1 + y)}
or
${(x!1) +
y}
, depending on which interpretation you meant.
That's needed because due to a programming mistake in FreeMarker
2.3.x, the precedence of
(when it's used as
default value operator) is very low at its right side. This
means that, for example,
${x!1 + y}
is
misinterpreted by FreeMarker as
${x!(1 + y)}
while it should mean
${(x!1) + y}
. This
programming error will be possibly fixed in some future version
(maybe 2.4), and you should not utilize this wrong behavior, so
that the fix can be enabled in your project!
If the default value is omitted, then it will be empty
string and empty sequence and empty hash at the same time. (This
is possible because FreeMarker allows multi-type values.) Note the
consequence that you can't omit the default value if you want it
to be
or
false
Example:
Template
(${mouse!})
<#assign mouse = "Jerry">
(${mouse!})
The output will be:
Output
()
(Jerry)
Warning!
Due to syntactical ambiguities
<@something
a=x! b=y />
will be interpreted as
<@something a=x!(b=y) />
, that is, the
b=y
will be interpreted as a comparison that
gives the default value for
, rather than
the specification of the
parameter. To
prevent this, write:
<@something a=(x!) b=y
/>
You can use this operator in two ways with non-top-level
variables:
Template
product.color!"red"
This will handle if
color
is missing
inside
product
(and returns
"red"
if so), but will not handle if
product
is missing. That is, the
product
variable itself must exist, otherwise
the template processing will die with error.
Template
(product.color)!"red"
This will handle if
product.color
is
missing. That is, if
product
is missing, or
product
exists but it does not contain
color
, the result will be
"red"
, and no error will occur. The important
difference between this and the previous example is that when
surrounded with parentheses, it is allowed for any component of
the expression to be undefined, while without parentheses only the
last component of the expression is allowed to be
undefined.
Of course, the default value operator can be used with
sequence sub variables as well:
Template
<#assign seq = ['a', 'b']>
${seq[0]!'-'}
${seq[1]!'-'}
${seq[2]!'-'}
${seq[3]!'-'}
the outpur will be:
Output
A negative sequence index (as
seq[-1]!'-'
) will always cause an error, you
can't suppress that with this or any other operator.
Missing value test operator
Synopsis:
unsafe_expr
??
or
unsafe_expr
)??
This operator tells if a value is missing or not. Depending
on that, the result is either
true
or
false
Example. Assume no variable called
mouse
is present:
Template
<#if mouse??>
Mouse found
<#else>
No mouse found
#if>
Creating mouse...
<#assign mouse = "Jerry">
<#if mouse??>
Mouse found
<#else>
No mouse found
#if>
The output will be:
Output
No mouse found
Creating mouse...
Mouse found
With non-top-level variables the rules are the same as with
the default value operator, that is, you can write
product.color??
and
(product.color)??
Assignment Operators
These are actually not expressions, but parts of the syntax of
the assignment directives, such as
assign
local
and
global
. As
such, they can't be used anywhere else.
<#assign x += y>
is shorthand for
<#assign x = x + y>
<#assign x
*= y>
is shorthand for
<#assign x = x *
y>
, and so on.
<#assign x++>
differs from
<#assign x += 1>
(or
<#assign x
= x + 1>
) in that it always does arithmetical addition
(and fails if the variable is not a number), while the others are
overloaded to do string and sequence concatenation and hash
addition.
<#assign x-->
is shorthand for
<#assign x -= 1>
Note:
The shorthand operators (like
+=
++
, etc.) are only supported since FreeMarker
2.3.23. Before that, you could only use
in
itself, as in
<#assign x = x + 1>
Local lambdas
FreeMarker doesn't support general purpose lambdas (unlike
Java). The usage of lambdas is restricted to the parameters of
certain
built-ins
like:
filter
map
take_while
drop_while
The reason of this restriction is that FreeMarker doesn't
implement binding/capturing variables that are referred from the
lambda, instead it ensures that the evaluation of the lambda happens
before the enclosing variable scope is ended. Hence, and to
differentiate them from "real" lambdas, these are
called
local
lambdas.
The syntax of lambdas is like
name1
name2
...
nameN
) ->
expression
. If there's only a
single argument, the parentheses can be omitted:
name1
->
expression
As the right side of the
->
is just a
single expression, if you need complex logic there, you probably
want to move that into a
function
, as the you can use
directives like
if
list
, etc.
In that case though, you don't need a lambda expression, as all
built-ins that support a lambda parameter, also support passing in a
function directly. For example, instead of
seq?map(it ->
myMapper(it))
you should just write
seq?map(myMapper)
The argument specified in a lambda expression can hold the
missing (Java
null
) value. Reading a lambda
argument never falls back to higher scope, so a variable with
identical name will not interfere when accessing the lambda
parameter. Therefore something like
seq?filter(it ->
it??)
, which filters out missing element from the
sequence, will work reliably.
Parentheses
Parentheses can be used to group any expressions. Some
examples:
Template
<#-- Output will be: -->
${3 * 2 + 2} <#-- 8 -->
${3 * (2 + 2)} <#-- 12 -->
${3 * ((2 + 2) * (1 / 2))} <#-- 6 -->
${"green " + "mouse"?upper_case} <#-- green MOUSE -->
${("green " + "mouse")?upper_case} <#-- GREEN MOUSE -->
<#if !(color == "red" || color == "green")>
The color is nor red nor green
#if>
Note that the parentheses of a
method call
expressions
have nothing to do with the parentheses used for
grouping.
White-space in expressions
FTL ignores superfluous
white-space
in expressions. So
these are totally equivalent:
Template
${x + ":" + book.title?upper_case}
and
Template
${x+":"+book.title?upper_case}
and
Template
${
+ ":" + book . title
? upper_case
Comments in expressions
Expression may contain comments anywhere where they can
contain ignored white-space (
see above
). Comments
look like
<#-- ... -->
or as
[#--
... --]
. Example:
Template
<#assign x <#-- A comment --> = 123 <#-- A comment -->>
<#function f(x <#-- A comment -->, y <#-- A comment -->)>
<#return <#-- A comment --> 1 <#-- A comment -->>
#function>
<#assign someHash = {
"foo": 123, <#-- A comment -->
"bar": x <#-- A comment --> + 1,
<#-- A comment -->
"baaz": f(1 <#-- A comment -->, 2 <#-- A comment -->)
} <#-- A comment -->>
Operator precedence
The following table shows the precedence assigned to the
operators. The operators in this table are listed in precedence
order: the higher in the table an operator appears, the higher its
precedence. Operators with higher precedence are evaluated before
operators with a relatively lower precedence. Operators on the same
line have equal precedence. When binary operators (operators with
two "parameters", as
and
) of equal precedence appear next to each other,
they are evaluated in left-to-right order.
Operator group
Operators
highest precedence operators
subvarName
subStringRange
] . ?
methodParams
expr
expr
??
unary prefix operators
expr
expr
!expr
multiplicative operators
* / %
additive operators
+ -
numerical ranges
..
..<
..!
..*
relational operators
< > <= >=
(and equivalents:
gt
lt
, etc.)
equality operators
== !=
(and equivalents:
logical "and" operator
&&
logical "or" operator
||
local lambda
->
For those of you who know C, Java language or JavaScript, note
that the precedence rules are the same as in those languages, except
that FTL has some operators that do not exist in those
languages.
The default value operator
exp
exp
is not yet in the table because of a programming mistake, which will
be only fixed in FreeMarker 2.4 due to backward compatibility
constraints. It meant to be a "highest precedence operator", but in
FreeMarker 2.3.x the precedence on its right side is very low by
accident. So if you have a composite expression on the right side,
always use paranthesses, etiher like
x!(y + 1)
or
like
(x!y) + 1
. Never write just
x!y +
Previous
Next
Overview
What is FreeMarker?
Version history
FAQ
License
Often used / Reference
Try template online
Expressions cheatsheet
#directives
?built_ins
.special_vars
Configuration settings
Community
Github project page
Report a bug
Report security vulnerability
Get help on StackOverflow
Announcements on Twitter
Discuss on mailing lists
Github
Stack Overflow
Edited with XMLMind XML Editor
Last generated:
2025-06-22 15:04:39 GMT
, for Freemarker 2.3.34
1999
–2025
The Apache Software Foundation
. Apache FreeMarker, FreeMarker, Apache, the Apache feather logo, and the Apache FreeMarker project logo are trademarks or registered trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.