Appendix A FAQ
Translations: Chinese in the Chinese translation of the Manual (PDF), Serbo-Croatian (based on FreeMarker 2.3.19)
Note: JSP 1.x was really bad as an MVC template engine because it was not made for that, so I don't deal with that here. We compare FreeMarker with the JSP 2.0 + JSTL combo.
FreeMarker Pros:
-
FreeMarker is not tied to Servlets, networking or the Web; it is just a class library to generate text output by merging a template with Java objects (the data-model). You can execute templates anywhere and anytime; no HTTP request forwarding or similar tricks needed, no Servlet environment needed at all. Because of this you can easily integrate it into any system.
-
No servlet specific scopes and other highly technical things in templates. It was made for MVC from the beginning, it focuses only on the presentation.
-
You can load the templates from anywhere; from the class path, from a data-base, etc.
-
Locale-sensitive number and date formatting by default. Since we mostly output for a human audience all you need to do is just write ${x} rather than <fmt:formatNumber value="${x}" />. You can easily switch this behavior and output non-localized numbers by default.
-
Much easier to define ad-hoc macros and functions.
-
No sweeping errors under the carpet. Missing variables will cause an error by default, and not silently default to arbitrary values. Also, null-s are not treated silently as 0/false/empty string. See more about this here...
-
``Object wrapping''. This lets you show the objects to templates in a customized, presentation oriented way (e.g. see here how a W3C DOM nodes can be seen by templates using this technology.)
-
Macros and functions are just variables (compare it to how JSP custom tags work), so they can be easily passed around as parameter values, put into the data-model, ...etc, just like any other value.
-
Easier to read, more terse syntax. For example: <#if x>...</#if> instead of <c:if test="${x}">...</c:if>
-
Virtually unnoticeable delay when visiting a page for the first time (or after it was changed), because no expensive compilation happens.
FreeMarker Cons:
-
Not a ``standard''. There are fewer tools and IDE integrations, fewer developers knows it and there's much less industry support in general. (However, JSP tag libraries can work in FreeMarker templates with the proper setup, unless they are using .tag files.)
-
Since macros and function are just variables, incorrect directive and parameter names and missing required parameters can be detected only on runtime.
-
Its syntax doesn't follow the HTML/XML rules apart from some visual similarity, which is confusing for new users. (It's the price of the terseness...)
-
Doesn't work with JSF. (It could work technically, but nobody has implemented that yet.)
You may read this if you are considering replacing JSP with FreeMarker: Programmer's Guide/Miscellaneous/Using FreeMarker with servlets/Using FreeMarker for ``Model 2''
To recapitulate what's this entry is about: FreeMarker by default treats an attempt to access a non-existent variable or a null value (this two is the same for FreeMarker) as error, which aborts the template execution.
First of all, you should understand the reason of being picky. Most scripting languages and template languages are rather forgiving with missing variables (and with null-s), and they usually treat them as empty string and/or 0 and/or logical false. This behavior has several problems:
-
It potentially hides accidental mistakes, like a typo in a variable name, or when the template author refers to a variable that the programmer doesn't put into the data-model for that template, or for which the programmer uses a different name. Human beings are prone to do such mistakes, while computers are not, so missing this opportunity that the template engine can show these errors is a bad business. Even if you very carefully check the output of the templates during development, it is easy to look over mistakes like <#if hasWarnigs>print warnings here...</#if>, which would then silently never print the warnings, since you have mistyped the variable name. Also think about maintenance, when you later modify your application; probably you will not re-check templates (many applications has hundreds of them) that carefully each time, for all possible scenarios. Unit tests typically doesn't cover web page content very good either (if you have them at all...); they mostly only checks certain manually set patterns in the web page, so they will often gloss though changes that are actually bugs. But if the page fails with exception, that's something human testers will notice and unit sets will notice, and in production the maintainers will notice (assuming somebody check error logs).
-
Makes dangerous assumptions. The script language or template engine knows nothing about the application domain, so when it decides the value of something that it doesn't know to be 0/false, it is a quite irresponsible and arbitrary thing. Just because it's not know what's your current balance at your bank, can we just say it's $0? Just because it is not known if a patient has penicillin allergy, we can just say he/she doesn't have it? Just consider the implications of such mistakes. Showing an error page is often better than showing incorrect information that formally looks good.
Being not picky is mostly sweeping under the carpet in this case (not facing with the problems), which of course most people feels more convenient, but still, we believe that in most cases being strict will save your time and increase your software quality on the long run.
On the other hand, we recognize that there are cases where you don't want FreeMarker to be that picky with good reason, and there is solution for them:
-
It's often normal that your data-model contains null-s or have optional variables. In such cases use these operators. If you use them too often, try to rethink your data-model, because depending on them too much won't just make the templates too verbose, but increases the probability of hiding errors and printing arbitrary incorrect output (for the reasons described earlier).
-
In some application you may rather want to show an incomplete/damaged page than an error page. In this case you can use another error handler than the default one. A custom error handler can skip the problematic part instead of aborting the whole page rendering. Note, however, that although the error handlers don't give arbitrary default values to variables, for pages that show critical information it's maybe still better to show an error page.
-
If the pages contain parts that aren't critically important (like side bars), another feature you may interested in is the attempt/recover directives.
Are you sure that you are using the documentation written for the same version of FreeMarker that you actually use? Especially, note that our online documentation is for the latest usable FreeMarker release. You may use an older release.
Are you sure that the Java class loader finds the same freemarker.jar that you expect to use? Maybe there is an older version of freemarker.jar around, which has higher priority. To check this, try to print the version number in a template with ${.version}. If it dies with ``Unknown built-in variable: version'' error message, then you use a release before 2.3-final or 2.2.8, but you can still try to get the version number in the Java code of your application with Configuration.getVersionNumber(). If this method is not present either, then you are using an early 2.3-preview, or a version before 2.2.6.
If you suspect that the problem is that you have multiple freemarker.jar-s, the typical culprit is that some module has a Maven dependency with group ID freemarker, as opposed to org.freemarker, while you have declared a dependency on org.freemarker. In this case you will have to exclude the freemarker dependency.
If you think that the documentation or FreeMarker is wrong, please report it using the bug tracker, or the mailing list. Thank you!
FreeMarker uses the locale-sensitive number formatting capability of the Java platform. The default number format for your locale may uses grouping or other unwanted formatting. To prevent this, you have to override the number format suggested by the Java platform with the number_format FreeMarker setting. For example:
| |||
Note however than humans often find it hard to read big numbers without grouping separator. So in general it is recommended to keep them, and in cases where the numbers are for ''computer audience'' (which is confused on the grouping separators), use the c built-in. For example:
| |||
Different countries use different decimal/grouping separator symbols. If you see incorrect symbols, then probably your locale is not set properly. Set the default locale of the JVM or override the default locale with the locale FreeMarker setting. For example:
| |||
However, sometimes you want to output a number not for human audience, but for ``computer audience'' (like you want to print a size in CSS), in which case you must use dot as decimal separator, regardless of the locale (language) of the page. For that use the c built-in, for example:
| |||
Unlike numbers, booleans has no commonly accepted format, not even a common format within the same page. Like when you show on a HTML page if a product is washable, you will hardly want to show for the visitor "Washable: true", but rather "Washable: yes". So we force the template author (by ${washable} causing error) to find out with his human knowledge how the boolean value should be shown at the given place. The common way of formatting a boolean is like ${washable?string("yes", "no")}, ${caching?string("Enabled", "Disabled")}, ${heating?string("on", "off")}, etc.
However, there are two cases where this gets impractical:
-
When printing boolean to generate computer language output, and hence you want true/false, use ${someBoolean?c}. (This requires at least FreeMarker 2.3.20. Before that, the common practice was writing ${someBoolean?string}, however that's dangerous because its output depends on the boolean format settings, whose default is "true"/"false".)
-
When you have format most of the booleans on the same way. In this case you can set the boolean_format setting (Configuration.setBooleanFormat) to reflect that, and then since FreeMarker 2.3.20 you can just write ${someBoolean}.
Starting from FreeMarker 2.3.4 you can use [ and ] instead of < and >. For more details read this...
FreeMarker has no limitations regarding the characters used in variable names, nor regarding the length of the variable names, but for your convenience try to chose variable names that can be used with the simple variable reference expressions (see it here). If you have to choose a more extreme variable name, that's not a bid problem either: see here.
If you have a variable with strange name, such as foo-bar, FreeMarker will misinterpret what do you want when you write thing as ${foo-bar}. In this concrete case, it will believe that you want subtract the value of bar from foo. This FAQ entry explains how to handle situations like this.
First of all it should be clean that these are just syntactical problems. FreeMarker has no limitations regarding the characters used in variable names, nor regarding the length of the variable names, but sometimes you need to use syntactical tricks.
If you want to read the variable: Use the square bracket syntax. An example of square bracket syntax is baaz["foo"], which is equivalent with baaz.foo. As the subvariable name with the square bracket syntax is a string literal (in fact, arbitrary expression), it let you write baaz["foo-bar"]. Now you may say that it can be used for hash subvariables only. Yes, but top-level variables are accessible through special hash variable .vars. For example, foo is equivalent with .vars["foo"]. So you can also write .vars["foo-bar"]. Naturally, this trick works with macro invocations too: <@.vars["foo-bar"]/>
If you want to create or modify the variable: All directives that let you create or modify a variable (such as assign, local, global, macro, function, etc.) allows the quotation of the destination variable name. For example, <#assign foo = 1> is the same as <#assign "foo" = 1>. So you can write things like <#assign "foo-bar" = 1> and <#macro "foo-bar">.
On JSP pages you quote all parameter (attribute) values, it does not mater if the type of the parameter is string or boolean or number. But since custom tags are accessible in FTL templates as plain user-defined FTL directives, you have to use the FTL syntax rules inside the custom tags, not the JSP rules. Thus, according to FTL rules, you must not quote boolean and numerical parameter values, or they are interpreted as string values, and this will cause a type mismatch error when FreeMarker tries to pass the value to the custom tag that expects non-string value.
For example, the flush parameter to Struts Tiles insert tag is boolean. In JSP the correct syntax was:
| |||
but in FTL you should write:
| |||
Also, for similar reasons, this is wrong:
| |||
and you should write:
| |||
(Not flush=${needFlushing}!)
Not with <#include ...>, as that just includes another FreeMarker template without involving the Servlet container.
Since the inclusion method you look for is Servlet-related, and pure FreeMarker is unaware of Servlets or even HTTP, it's the Web Application Framework that decides if you can do this and if so how. For example, in Struts 2 you can do this like this:
| |||
If the FreeMarker support of the Web Application Framework is based on freemarker.ext.servlet.FreemarkerServlet, then you can also do this (since FreeMarker 2.3.15):
| |||
but if the Web Application Framework provides its own solution, then you may prefer that, after all it may does something special.
For more information about include_page read this...
Unfortunately, there is no simple general-purpose solution for this problem. The problem is that FreeMarker object wrapping is very flexible, which is good when you access variables from templates, but makes unwrapping on the Java side a tricky question. For example, it is possible to wrap a non-java.util.Map object as TemplateHashModel (FTL hash variable). But then, it can't be unwrapped to java.util.Map, since there is no wrapped java.util.Map around at all.
So what to do then? Basically there are two cases:
-
Directives and methods that are written for presentation purposes (like kind of ``tools'' for helping FreeMarker templates) should declare their arguments as TemplateModel-s and the more specific sub interfaces of that. After all, the object wrapping is about apparently transforming the data-model to something that serves the purpose of the presentation layer, and these methods are part of the presentation layer.
-
Methods that are not for presentation related tasks (but for business logic and like) should be implemented as plain Java methods, and should not use any FreeMarker specific classes at all, since according the MVC paradigm they must be independent of the presentation technology (FreeMarker). If such a method is called from a template, then it is the responsibility of the object wrapper to ensure the conversion of the arguments to the proper type. If you use the DefaultObjectWrapper or the BeansWrapper then this will happen automatically (but be sure you are using at least FreeMarker 2.3.3). Furthermore if you use BeansWrapper, then the method will surely get exactly the same instance that was earlier wrapped (as far as it was wrapped by the BeansWrapper).
The ``hash'' type of the FreeMarker Template Language (FTL) is not the same as Java's Map. FTL's hash is an associative array too, but it uses string keys exclusively. This is because it was introduced for subvariables (as password in user.password, which is the same as user["password"]), and variable names are strings.
So FTL's hashes are not general purpose associate arrays that could be used for looking up values with keys of arbitrary type. FTL is presentation oriented language, and it has no feature dedicated for that purpose. It has, however, methods. Methods are part of the data-model, and they can do all kind of fancy data-model related calculations, so of course you can add some methods to the data-model for Map lookup. The bad news is that the building of the data-model, as it's an application specific issue, is the task of the programmers who use FreeMarker, so it's their task to ensure that such methods are present there to serve the template authors. (However, when template authors need to call methods that are not about presentation, then consider if the data-model is simple enough. Maybe you should push some calculations back to the data-model building phase. Ideally the data-model contains what should be displayed, and not something that serves as the base of further calculations.)
If you read the programmer's guide, then you know that technically, the data-model is a tree of freemarker.template.TemplateModel objects. The building of the data-model usually (but not necessary) happens by automatically wrapping (enclosing) plain Java objects into TemplateModel objects. The object that does this wrapping is the object wrapper, and it's specified when you configure FreeMarker. FreeMarker comes with a few object wrapper implementations out-of-the-box, and probably the most widely used of them is freemarker.ext.beans.BeansWrapper. If you use an instance of this as the object wrapper, then java.util.Map-s you put into the data-model will also act as a method, so you can write myMap(myKey) in the template, that will internally call Map.get(myKey). There will be no restriction regarding the type of myKey, as Map.get(Object key) has no such restriction. If the value of myKey was wrapped with BeansWrapper or other object wrapper whose wrapped objects support unwrapping, or it is given as literal in the template, then the value will be automatically unwrapped to plain Java object before the actual invocation of the Map.get(Object key) method, so it will not be invoked with TemplateModel-s.
But there still will be a problem. Java's Map is particular about the exact class of the key, so for numerical keys calculated inside the templates you will have to cast them to the proper Java type, otherwise the item will not be found. For example if you use Integer keys in a Map, then you have to write ${myMap.get(123?int)}. This is an ugly effect caused by that FTL's deliberately simplified type system just has a single numerical type, while Java distinguishes a lot of numerical types. (Ideally, in the above case, the programmers ensure that the get method automatically converts the key to Integer, so it's not the problem of the template author. This can be done with wrapper customization, but the wrapper has to know that the particular Map object uses Integer keys, which assumes application specific knowledge.) Note that the casting is not needed when the key value comes directly from the data-model (i.e. you didn't modified its value with arithmetical caluclations in the template), including the case when it's the return value of a method, and it was of the proper class before wrapping, because then the result of the unwrapping will be of the original type.
Certainly you are using BeansWrapper as your object wrapper, or a custom subclass of it, and the simpleMapWrapper property of that is left to false. Unfortunatelly, it's the default (for backward compatibility), so you have to explicitly set it to true where you create the object wrapper.
First of all, you may don't want to modify the sequence/hash, just concatenate (add) two or more of them, which results in a new sequence/hash, rather than modifying an existing one. In this case use the sequence concatenation and hash concatenation operators. Also, you may use the subsequence operator instead of removing sequence items. However, be aware of the performance implications: these operations are fast, but the hashes/sequences that are the result of many subseqent applications of these operations (i.e. when you use the result of the operation as the input of yet another operation, and so on) will be slow to read.
Now if you still want to modify sequences/hashes, then read on...
The FreeMarkes Template Language doesn't support the modification of sequences/hashes. It's for displaying already calculated things, not for calculating data. Keep templates simple. But don't give it up, you will see some advices and tricks bellow.
The best is if you can divide the work between the data-model builder program and the template so that the template doesn't need to modify sequences/hashes. Maybe if you rethink your data-model, you will realize this is possible. But, seldom there are cases where you need to modify sequences/hashes for some complex but purely presentation related algorithms. It seldom happens, so think twice whether that calculation (or parts of it) rather belongs to the data-model domain than to the presentation domain. Let's assume you are sure it belongs to the presentation domain. For example, you want to display a keyword index on some very smart way, whose algorithm need you to create and write some sequence variables. Then you should do something like this (ugly situations has ugly solutions...):
| |||
That is, you move out the complex part of the presentation task from the template into Java code. Note that it doesn't affect the data-model, so the presentation is still kept separated from other the other application logic. Of course the drawback is that for this the template author will need the help of a Java programmer, but for complex algorithms that's probably needed anyway.
Now, if you still say you need to modify sequences/hashes directly with the FreeMarker template, here are two solutions, but please read the warning after them:
-
You can write a TemplateMethodModelEx and TemplateDirectiveModel implementation that can modify certain types of sequences/hashes. Just certain types, because TemplateSequenceModel and TemplateHashModel doesn't have methods for modification, so you will need the sequence or hash to implement some additional methods. An example of this solution can be seen in FMPP. It allows you to do things like this (pp stores the services provided by FMPP for templates):
<#assign a = pp.newWritableSequence()> <@pp.add seq=a value="red" />
The pp.add directive works only with sequences that were created with pp.newWritableSequence(). So for example the template author can't modify a sequence that comes from the data-model with this.
-
A sequence can have some methods/directives if you use a customized wrapper (so you can <@myList.append foo />). (Also, if you use BeansWrapper and configure it so it exposes the public methods, you can use the Java API for variables that are for java.util.Map-s and java.util.List-s. Just like with Apache Velocity.)
But beware, these solutions have a problem: The sequence concatenation, sequence slice operator (like seq[5..10]) and ?reverse do not copy the original sequence, just wraps it (for efficiency), so the resulting sequence will change if the original sequence is changed later (an abnormal aliasing effect). The same problem exists with the result of hash concatenation; it just wraps the two hashes, so the resulting hash will magically change if you modify the hashes you have added earlier. As a work-around, after you did the above problematic operations, either be sure you will not modify the objects that were used as input, or create a copy of the result with a method provided by the solution described in above two points (e.g. in FMPP you could do <#assign b = pp.newWritableSequence(a[5..10])> and <#assign c = pp.newWritableHash(hashA + hashB)>). Of course this is easy to miss... so again, rather try to build the data-model so you will not need to modify collections, or use a presentation task helper class as was shown earlier.
The FreeMarker template language doesn't know the Java language null at all. It doesn't have null keyword, and it can't test if something is null or not. When it technically faces with a null, it treats it exactly as a missing variable. For example, both if x is null in the data-model and if it's not present at all, ${x!'missing'} will print ``missing'', you can't tell the difference. Also, if for example you want to test if a Java method has returned null, just write something like <#if foo.bar()??>.
You may interested in the rationale behind this. From the viewpoint of the presentation layer a null and non-existent thing is almost always the same. The difference between this two is usually just a technical detail, which is rather the result of implementation details than of the application logic. That you can't compare something to null (unlike in Java); it doesn't make sense to compare something with null in a template, since the template language doesn't do identity comparison (like the Java == operator when you compare two objects) but the more common sense value comparison (like Java's Object.equals(Object); that doesn't work with null either). And how could FreeMarker tell if something concrete equals with something that is missing and thus unknown? Or if two missing (unknown) things are equal? Of course these questions can't be answered.
There is at least one problem with this null-unaware approach. When you call a Java method from a template, you may want to pass a null value as argument (since the method was designed to be used in Java language, where the concept of null is known). In this case you can exploit a bug of FreeMarker (that we will not fix until we provide a correct solution for passing null values to a method): if you specify a missing variable as the argument, then it will not cause an error, but a null will be passed to the method instead. Like foo.bar(nullArg) will call the bar method with null as argument, assuming that there is no varaible exists with ``nullArg'' name.
Capture the output into a variable with the assign or local directive. For example:
| |||
This is because the character that you want to print can't be represented with the charset (encoding) used for the output stream, so the Java platform (not FreeMarker) substitutes the problematic character with question mark. In general you should use the same charset for the output as for the template (use the getEncoding() method of the template object), or which is even safer, you should always use UTF-8 charset for the output. The charset used for the output stream is not decided by FreeMarker, but by you, when you create the Writer that you pass to the process method of the template.
Example: Here I use UTF-8 charset in a servlet:
| |||
Note that the question marks (or other substitution characters) may be produced outside FreeMarker, in which case the above obviously will not help. For example a bad/missconfigured database connection or JDBC driver may bring the text already with substitution characters in it. HTML forms are another potential source of encoding problems. It's a good idea to print the numerical code of the characters of the string on various places, to see where the problem occurs first.
You can read more about charsets and FreeMarker here...
First of all, be sure your application is designed well: templates should display data, and almost never calculate data. If you are still sure you want to do it, read on...
When you use <#assign x = "foo">, then you do not actually modify the data-model (since that is read-only, see: Programmer's Guide/Miscellaneous/Multithreading), but create the x variable in the runtime environment of the processing (see Programmer's Guide/Miscellaneous/Variables). The problem is that this runtime environment will be discarded when Template.process returns, as it was created for a single Template.process call:
| |||
To prevent this, you can do the below, which is equivalent with the above, except that you have chance to return the variables created in the template:
| |||
In general you shouldn't allow that, unless those users are system administrators or other trusted personnel. Consider templates as part of the source code just like *.java files are. If you still want to allow users to upload templates, here are what to consider:
-
Denial-of-Service (DoS) attacks: It's trivial to create templates that run practically forever (with a loop), or exhaust memory (by concatenating to a string in a loop). FreeMarker can't enforce CPU or memory usage limits, so this is something that has no solution on the FreeMarker-level.
-
Data-model and wrapping (Configuration.setObjectWrapper): By default the data-model gives access to the full public API of the Java objects that you have put into the it (with some exceptions). To avoid that, you have to construct the data-model so that it only exposes the things that are necessary for the template. For that, use SimpleObjectWrapper and create the data-model purely from Map-s, List-s, Array-s, String-s, Number-s, Boolean-s and Date-s. Or, you can implement your own extremely restrictive ObjectWrapper, which for example could expose your POJO-s safely.
-
Template-loader (Configuration.setTemplateLoader): Templates may load other templates by name (by path), like <#include "../secret.txt">. To avoid loading sensitive data, you have to use a TemplateLoader that double-checks that the file to load is something that should be exposed. FreeMarker tries to prevent the loading of files outside the template root directory regardless of template loader, but depending on the underlying storage mechanism, exploits may exist that FreeMarker can't consider (like, just as an example, ~ jumps to the user directory). Note that freemarker.cache.FileTemplateLoader checks the canonical paths, so that's maybe a good candidate for this task, yet, adding a file extension check (file must be *.ftl) is maybe a good idea.
-
The new built-in (Configuration.setNewBuiltinClassResolver, Environment.setNewBuiltinClassResolver): It's used in templates like "com.example.SomeClass"?new(), and is important for FTL libraries that are partially implemented in Java, but shouldn't be needed in normal templates. While new will not instantiate classes that are not TemplateModel-s, FreeMarker contains a TemplateModel class that can be used to create arbitrary Java objects. Other "dangerous" TemplateModel-s can exist in you class-path. Plus, even if a class doesn't implement TemplateModel, its static initialization will be run. To avoid these, you should use a TemplateClassResolver that restricts the accessible classes (possibly based on which template asks for them).
It's not possible (yet), but something very similar is possible if you write a class that implements freemarker.template.TemplateMethodModelEx or freemarker.template.TemplateDirectiveModel respectively, and then where you were write <#function my ...>...</#function> or <#macro my ...>...</#macro> you write <#assign my = "your.package.YourClass "?new()> instead. Note that using the assign directive for this works because functions (and methods) and macros are just plain variables in FreeMarker. (For the same reason you could also put TemplateMethodModelEx or TemplateDirectiveModel instances into the data-model before calling the template, or into the shared variable map (see: freemarker.template.Configuration.setSharedVariable(String, TemplateModel)) when you initialize the application.)
It's because FreeMarker does not find any logging system. To fix this, you must make available one of the following logging systems for your application: SLF4J (recommended), Apache Commons Logging, Log4J (org.apache.log4j), Avalon (org.apache.log), or use J2SE 1.4 or later (that contains java.util.logging). That is, the class-loader used with your application must find one of the mentioned classes. Until 2.4, if you want to use SLF4J or Commons Logging you need to do some extra steps; see here...
First of all, use RETHROW_HANDLER instead of the default DEBUG_HANDLER (for more information about template exception handlers read this...). Now FreeMarker will not print anything to the output when an error occurs, so the control is in your hands. After you have caught the exception of Template.process(...) basically you can follow two strategies:
-
Call httpResp.isCommitted(), and if that returns false, then you call httpResp.reset() and print a ``nice error page'' for the visitor. If the return value was true, then try to finish the page be printing something that makes clear for the visitor that the page generation was abruptly interrupted because of an error on the Web server. You may have to print a lot of redundant HTML end-tags and set colors and font size to ensure that the error message will be actually readable in the browser window (check the source code of the HTML_DEBUG_HANDLER in src\freemarker\template\TemplateException.java to see an example).
-
Use full page buffering. This means that the Writer doesn't send the output to the client progressively, but buffers the whole page in the memory. Since you provide the Writer instance for the Template.process(...) method, this is your responsibility, FreeMarker has nothing to do with it. For example, you may use a StringWriter, and if Template.process(...) returns by throwing an exception, then ignore the content accumulated by the StringWriter, and send an error page instead, otherwise you print the content of StringWriter to the output. With this method you surely don't have to deal with partially sent pages, but it can have negative performance implications depending on the characteristic of the pages (for example, the user will experience more response delay for a long page that is generated slowly, also the server will consume more RAM). Note that using a StringWriter is surely not the most efficient solution, as it often reallocates its buffer as the accumulated content grows.
We won't change the standard version, because a lot of templates depend on it.
Our view is that the editors that break template code are themselves broken. A good editor should ignore, not mangle, what it doesn't understand.
You maybe interested in that starting from FreeMarker 2.3.4 you can use [ and ] instead of < and >. For more details read this...
First of all, don't forget that FreeMarker is only the view rendering component in an MVC system. Furthermore MVC templates tend to be simple: many static text with a few interpolations and loops and conditional block. So it is not like PHP or Model 1 JSP; your application performance is not affected that much by the execution time of templates.
FreeMarker is certainly fast enough that it will only very rarely be a bottleneck in your application. Rather, other factors such as the speed of the data-base operations or network bandwidth will likely dominate. The impact of FreeMarker performance could be noticeable only for really busy sites (say, over 30 hits per second per server), where almost all database data is cached. If you are finding FreeMarker slow, do make sure that the cache of parsed templates works well (Configuration.getTemplate be default uses caching). Parsing a template file is a relatively costly step; in most long-running server-side applications, you will want to parse a template once and have it be used many times. (Note that FreeMarker 2.1.4 and earlier versions have bugs that sometimes can ruin caching.)
FreeMarker 2.1 is slower than 1.7.1. This surely depends on your templates, but it could be slower by a factor of 2 or 3. But again, it does not means that response time will be 2 or 3 times slower; most FreeMarker user simply should not be able to perceive the change in the final response time.
In FreeMarker 2.2, Template has an undocumented method for examining the parsed template: getRootTreeNode.
But listing all accessed variables is not possible, because variable names can be dynamically generated from data. However, there's a more important reason why FreeMarker doesn't support this. The design of FreeMarker is based on the idea of a separation between business objects and presentation objects. This separation takes two forms:
-
The templates know what data to expect, but they don't know how it's generated.
-
The business objects know what data to produce, but they don't know how it's going to be displayed. Therefore, they don't know anything about templates.
Since the business objects don't rely on the templates, if you need to use them with some other presentation system, you won't have to rewrite your application.
FreeMarker 2.0 was a complete rewrite of FreeMarker 1.x, by a new author. The 1.x series continues as separated project: FreeMarker Classic. Since 2.x follows different philosophy than 1.x, 2.0x releases were immature despite the high major version number. This caused further radical changes between 2.01 and 2.1. As of 2.1 things were much more matured, and 2.2 is almost backward compatible with 2.1. We hope that this tendency continues.
Currently, the rule is that releases with different second version number (as 2.1.x and 2.2.x) are not (fully) compatible. Releases where only the third version number differs (as 2.2.1 and 2.2.6) are compatible.
We always provide backward compatible bugfix releases for the released versions. So basically, you don't have to switch to a new, non-backward compatible release in an already written product. It's a something for something situation... FreeMarker recovers faster from design mistakes than many other projects, but the price of this is that major releases are not backward compatible. This is admittedly not optimal, it would be better if there are fewer design mistakes... but, well, it is the reality.
No. As of 2.0, FreeMarker is released under a BSD-style license. This means that source or binary distributions may be made freely, and can be included in other products, whether commercial or open source.
The only restrictions apply to the copyright of FreeMarker itself, and the use of FreeMarker or its contributors as endorsements of your own product. See the LICENSE for further details.
If you use FreeMarker, we hope you'll send us a link to some information about your product, but that's optional as well.