![]() |
||
|
||
![]() |
1. JSP versus FreeMarker? |
|||||||||||||||||||||||||||||||||||||||||
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 Cons:
You may read this if you are considering replacing JSP with FreeMarker: Programmer's Guide/Using FreeMarker with servlets/Using FreeMarker for ``Model 2'' | |||||||||||||||||||||||||||||||||||||||||
2. Velocity versus FreeMarker? |
|||||||||||||||||||||||||||||||||||||||||
Velocity is a simpler, more lightweight tool. Thus, it does not address many tasks that FreeMarker does, and its template language is less powerful in general, but it is simpler; visit http://freemarker.org/fmVsVel.html for details. Currently (2005) Velocity has wider third party support and larger user community. | |||||||||||||||||||||||||||||||||||||||||
3. Why is FreeMarker so picky about null-s and missing variables, and what to do with it? |
|||||||||||||||||||||||||||||||||||||||||
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:
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 in 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:
| |||||||||||||||||||||||||||||||||||||||||
4. The documentation writes about feature X, but it seems that FreeMarker doesn't know that, or it behaves in a different way as documented, or a bug that was supposedly fixed is still present. |
|||||||||||||||||||||||||||||||||||||||||
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 (such as in the Ant lib directory), 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 think that the documentation or FreeMarker is wrong, please report it using the bug tracker, or the mailing list, or the forums on http://sourceforge.net/projects/freemarker/. Thank you! | |||||||||||||||||||||||||||||||||||||||||
5. Why does FreeMarker print the numbers with strange formatting (as 1,000,000 or 1 000 000 instead of 1000000)? |
|||||||||||||||||||||||||||||||||||||||||
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 in the FreeMarker configuration. 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'' that is confused on the grouping separators, use the c built-in. For example:
| |||||||||||||||||||||||||||||||||||||||||
6. Why does FreeMarker print bad decimal and/or grouping separator symbol (as 3.14 instead of 3,14)? |
|||||||||||||||||||||||||||||||||||||||||
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 in the FreeMarker configuration:
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 (like ${x?c}). | |||||||||||||||||||||||||||||||||||||||||
7. The < and > of FreeMarker tags confuses my editor or the XML parser. What to do? |
|||||||||||||||||||||||||||||||||||||||||
Starting from FreeMarker 2.3.4 you can use [ and ] instead of < and >. For more details read this... | |||||||||||||||||||||||||||||||||||||||||
8. What are the legal variable names? |
|||||||||||||||||||||||||||||||||||||||||
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. | |||||||||||||||||||||||||||||||||||||||||
9. How can I use variable (macro) names that contain space, dash or other special characters? |
|||||||||||||||||||||||||||||||||||||||||
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">. | |||||||||||||||||||||||||||||||||||||||||
10. Why do I get "java.lang.IllegalArgumentException: argument type mismatch" when I try to use X JSP custom tag? |
|||||||||||||||||||||||||||||||||||||||||
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}!) | |||||||||||||||||||||||||||||||||||||||||
11. How can I get the parameters to my plain-Java-method/TemplateMethodModelEx/TemplateTransformModel implementation as plain java.lang.*/java.util.* objects? |
|||||||||||||||||||||||||||||||||||||||||
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:
| |||||||||||||||||||||||||||||||||||||||||
12. Why I can't use non-string key in the myMap[myKey] expression? And what to do now? |
|||||||||||||||||||||||||||||||||||||||||
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 have a get(key) method, so you can write myMap.get(myKey) in the template. This is because, be default at least, this object wrapper exposes most public methods of the wrapped objects as methods in the data model. There will be no restriction regarding the type of myKey, because 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 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. Since Java's Map is particular about the exact class of the key, for numerical keys calculated inside the templates you will have to cast them to the proper 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... that 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 the original object. | |||||||||||||||||||||||||||||||||||||||||
13. How can I modify sequences (lists) and hashes (maps) in FreeMarker templates? |
|||||||||||||||||||||||||||||||||||||||||
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:
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. | |||||||||||||||||||||||||||||||||||||||||
14. What about null and the FreeMarker template language? |
|||||||||||||||||||||||||||||||||||||||||
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?default('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()?exists>. 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. | |||||||||||||||||||||||||||||||||||||||||
15. How can I use the output of a directive (macro) in expressions (as a parameter to another directive)? |
|||||||||||||||||||||||||||||||||||||||||
Capture the output into a variable with the assign or local directive. For example:
| |||||||||||||||||||||||||||||||||||||||||
16. Why do I have ``?''-s in the output instead of character X? |
|||||||||||||||||||||||||||||||||||||||||
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... | |||||||||||||||||||||||||||||||||||||||||
17. How to retrieve values calculated in templates after template execution done? |
|||||||||||||||||||||||||||||||||||||||||
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:
| |||||||||||||||||||||||||||||||||||||||||
18. Why is FreeMarker logging suppressed for my application? |
|||||||||||||||||||||||||||||||||||||||||
It is because FreeMarker does not find any logging system. To fix this, you must make available one of the following logging systems for your application: Avalon (org.apache.log), Log4J (org.apache.log4j), 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. | |||||||||||||||||||||||||||||||||||||||||
19. In my Servlet based application, how do I show a nice error page instead of a stack trace when error occurs during template processing? |
|||||||||||||||||||||||||||||||||||||||||
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:
| |||||||||||||||||||||||||||||||||||||||||
20. I'm using a visual HTML editor that mangles template tags. Will you change the template language syntax to accommodate my editor? |
|||||||||||||||||||||||||||||||||||||||||
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... | |||||||||||||||||||||||||||||||||||||||||
21. How fast is FreeMarker? Is it true that 2.x is slower than 1.x (FreeMarker classic)? |
|||||||||||||||||||||||||||||||||||||||||
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. | |||||||||||||||||||||||||||||||||||||||||
22. How can my Java classes ask a template for information about its structure (e.g. a list of all the variables)? |
|||||||||||||||||||||||||||||||||||||||||
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:
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. | |||||||||||||||||||||||||||||||||||||||||
23. Will you ever provide backward compatibility? |
|||||||||||||||||||||||||||||||||||||||||
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. | |||||||||||||||||||||||||||||||||||||||||
24. If we distribute FreeMarker with our product, do we have to release the source code for our product? |
|||||||||||||||||||||||||||||||||||||||||
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. |
![]() |
||
|
||
![]() |
![]() |
|
Page generated: 2006-03-15 13:49:01 GMT | FreeMarker Manual -- For FreeMarker 2.3.6 |