The first public release of FreeMarker 2.0 was on 18 March 2002. Here is a summary of the changes in the Lazarus release, with respect to the last stable release of FreeMarker Classic.
NOTA BENE:
Despite the changes delineated above, the Lazarus release is
almost entirely backward-compatible with FreeMarker Classic. We
believe that most existing code and templates
that work under FreeMarker Classic will continue working under
Lazarus, with at most minimal changes. In practice, the most common
cases where legacy template code is broken will be where assumptions
were made about numbers and strings being equivalent. Note that in
FreeMarker 2, 2 + 2 does not result in "22". The String "1" and the
number 1 are entirely different animals and thus, any code will be
broken if it relies on the boolean expression ("1"==1) being true.
There is a "classic compatibility mode" that can be set via:
Template.setClassCompatibility()
that can be set so
that Lazarus emulates some of the quirky behavior of FreeMarker
Classic. However, any code that relied on the above "features" of
FreeMarker classic really should be reworked. You are less likely to
run into the other incompatibilities that are listed above. If you
come across any other anomalies, please do tell us about them.
Support for Numerical operations, both arithmetic and boolean, as well as numerical ranges.
-
Scalars can now be either strings or numbers. (In FreeMarker Classic all scalars were strings.) The basic operations allowed are addition, subtraction, multiplication, division, and modulus using the
+
,-
,*
,/
, and%
operators respectively. Arbitrary-precision arithmetic with integers and floating point numbers are provided. Though our goal is definitely to follow the principle of least surprise, for backward compatibility, the+
operator still is used for string concatenation. If either the left hand side or the right hand side oflhs + rhs
is non-numerical, we revert to interpreting this as string concatenation. Thus, in FreeMarker 2, 2+2 evaluates to the number 4, while any of "2"+2 or 2+"2" or "2"+"2" evaluate to the string "22". In FreeMarker Classic, rather embarrassingly, all of the above, including 2+2, evaluated to the string "22". An attempt to use any other arithmetic operator besides the+
with non-numerical operands will cause an exception to be thrown. -
Output of a numerical expression can be made explicit via the alternative
#{....}
syntax. If the expression within the curly parentheses does not evaluate to a numerical value, an exception is thrown. The older ${....} syntax can evaluate to either a number or a string. In general, if, for logical reasons, the output must be numerical, it is preferable to use the #{...} syntax, since it adds an extra sanity check. Note that if, by some miracle, the character sequence "#{" occurs in your template, you will have to use a workaround to prevent problems. (The <noparse> directive is one possibility.) -
In this release, there is a facility for specifying the number of digits to show after the decimal point. The following code specifies to show at least 3 digits after the decimal point but not more than 6. This is optional. This option is only available if you use the #{...} syntax.
Template#{foo + bar ; m3M6}
(Note that the above is something of a stopgap measure. Future releases will move toward supporting fully internationalization and localization of number and currency formatting.
-
Numerical expressions can be used in boolean expressions via the comparison operators:
lt
,gt
,lte
, andgte
. In the web space, where FreeMarker is most used in practice, using the more natural operators such as < and > would tend to confuse HTML-oriented editors. An attempt to compare non-numerical expressions using these operators leads to aTemplateException
being thrown. If, by some coincidence, you have variables named "lt", "gt", "lte", or "gte", you will have to change their names, since they are now keywords in the language. -
Numerical ranges are supported.
Template<#list 1990..2001 as year> blah blah in the year ${year} blah </#list>
The left hand and right hand sides of the
..
operator must be numerical, or an exception is thrown. They also need not be literal numbers, but can be more complex expressions that evaluate to a numerical scalar value. Note that it is also possible to write a range that descends in value:Template<#list 2001..1990 as year> blah blah in the year ${year} blah blah </#list>
API Changes
-
The
TemplateNumberModel
interface and theSimpleNumber
implementation were added to support exposing numerical values. -
The
TemplateListModel
API in FreeMarker Classic had some design problems -- particularly in terms of supporting thread-safe code. It has been deprecated in favor of the following API's:TemplateCollectionModel
andTemplateSequenceModel
. TheSimpleList
class was refactored to implement the above interfaces (and paradoxically, does not implement the TemplateListModel interface.) Code that uses the deprecatedTemplateListModel
should be refactored. -
The Expose Package by Attila Szegedi has been made an integral part of the FreeMarker distribution and is now under the freemarker.ext.* hierarchy. This package provides advanced models for representing arbitrary Java objects as template models, for representing XML documents as template models, as well as classes to facilitate the integration of FreeMarker with servlets and Ant.
-
In FreeMarker Classic, there were some utility classes such as
freemarker.template.utility.Addition
etcetera that existed as workarounds for the lack of numerical operations in FreeMarker. Those have been removed and will probably not be missed. -
In FreeMarker Classic, the
SimpleScalar
object was mutable, it had asetValue
method. This was fairly obviously a design mistake. Any code that relied on this must be refactored. Note that in this release, bothSimpleScalar
and the newly introducedSimpleNumber
are both immutable and final.
Syntactical Miscellany
-
The if-elseif-else syntax was introduced. FreeMarker classic only had if-else. This construct should probably (in the opinion of the author of this document -- Revusky) be used in preference to switch-case since the switch-case with fall-through is a notoriously error-prone construct for most mortal men.
-
You can now do a multiple assignment in one <assign...> directive. For example:
<assign x = 1, y = price*items, message="foo">
-
A scalar will no longer be interpreted as a one-item list in a <list...> or <#foreach...> block. If you have code that relied on this feature, there is an easy workaround, since you can simply define a list literal with exactly one item.
Template<assign y=[x]> and then... <list y as item>...</list>