发布日期: 2015-07-05

FTL 部分的修改

  • 列表显示 (#list) 已经得到了一些专业的方便特性, 目标是人们在模板中一遍又一遍做的经典任务。

    • 新的 list 指令的子指令。 它们是 elseitems,来处理0长度列表的特殊情况, sep 来在迭代项之前插入分隔符。 更多细节,请参考 list 指令

    • 作用于循环变量的新内建函数var?index (废弃 var_index), var?counter (基于1的索引), var?has_next (废弃 var_has_next), var?is_firstvar?is_lastvar?item_parity (返回 "odd""even"), var?item_parity_capvar?item_cycle(...),等等。

  • 添加方便的赋值操作符,仅可以用于赋值指令 which can be used (当前是 #assign#global#local):

    • ++--: <#assign counter++><#assign counter = counter + 1> 是相等的。

    • +=-=, *=/=%=<#assign counter += 2><#assign counter = counter + 2> 是相等的。

  • 添加 then 内建函数,可以像三元操作符来使用: someBoolean?then(whenTrue, whenFalse)。 和很多其它语言的三元操作符相似,只有一个参数表达式会被评估。更多细节...

  • 添加 switch 内建函数, 可以像内联(表达式) switch-case-default 语句来使用: someValue?switch(case1, result1, case2, result2, ... caseN, resultN, defaultResult),这里 defaultResult 可以被忽略 (如果没有任何一个情形匹配上,那么就会有错误)。 更多细节...

  • 对模板语言部分标识符添加驼峰格式个支持(自定义名称不受影响)。 例如,现在 <#noEscape>${x?upperCase}</#noEscape><#setting numberFormat="0.0"><#ftl stripText=true> 都是合法的。 但在同一个模板中,FreeMarker 会需要你对所有模板语言部分的标识符一直使用相同的命名约定。 也可以对所有模板强制使用相同的命名约定,在Java中通过 Configuration.setNamingConvention(int) 来实现。 从后期的一些版本中,驼峰格式是推荐的约定,因为Java API用户从模板中调用也会用到它。

  • 添加新的 特殊变量.current_template_name.main_template_name。它们废弃了 .template_name,因为当在宏调用时,经常会崩溃。 新的 .current_template_name 通常返回包含引用特殊变量的模板名称,而 .main_template_name 通常返回最高模板的名称。

  • 很小的错误信息改进。比如,当 someMap[someNumber] 抱怨 someMap 不是序列或强迫为字符串时, 在常见问题的错误消息中添加提示。

  • Bug 修复,激活设置 incompatible_improvements 为 2.3.23: 有一个长期存在的解析时间规则称为 #break,在FTL源代码中, 必须在嵌套的可以打断的指令中出现,比如 #list#switch。 该检查可以绕过 #macro#function,比如: <#list 1..1 as x><#macro callMeLater><#break></#macro></#list><@callMeLater />。激活这个修改之后,它会作为解析时间错误被捕获。

Java 部分的修改

  • 添加 Configuration.setNamingConvention(int)。 默认情况下,FreeMarker 会自动检测用于模板语言部分的标识符的命名规则 (遗留的 和 驼峰格式),每个模板都是独立地进行。 该设置允许你强制使用一个命名规则。

  • Configuration (事实上,任意的 Configurable) 设置名称现在可以写作驼峰格式了。 例如,如果你从属性文件中配置 FreeMarker,你可以使用 defaultEncoding=utf-8 来代替 default_encoding=utf-8。你也可以混合使用两种命名规则 (驼峰格式,和传统的蛇形格式),而且 Configuration.setNamingConvention(int) 不影响这个行为。

  • 添加 Configuration.setTemplateUpdateDelayMilliseconds(long)Configuration.getTemplateUpdateDelayMilliseconds()。 它们废弃了 setTemplateUpdateDelay(int),使用第二种方案, 会基于Java习惯会导致误解。(而且那也没有成对的 getter 方法)

  • 当指定字符串时(在 java.util.Properties), template_update_delay 设置支持时间单元,比如 template_update_delay=500 ms

  • 添加 Environment.getCurrentTemplate() 方法,它会返回当前执行的模板(相对于主模板)。

  • 添加 WebappTemplateLoader.setAttemptFileAccess(boolean), 可以用于禁用遗留的尝试通过直接文件访问加载模板的技巧,那么模板更新就无需重启。 禁用URL连接缓存 (someURLBasedTemplateLoader.setURLConnectionUsesCaches(false), 从 incompatible_improvements 2.3.21 开始,这是默认的) 可能会在现代的Servlet容器中解决这个问题。

  • In the FreemarkerServlet TemplatePath init-param, paths (like /templates) can have a ?settings(...) postfix, with which you can set the JavaBean properties of the resulting TemplateLoader. For example: <param-value>/templates?settings(attemptFileAccess=false, URLConnectionUsesCaches=false)</param-value>

  • Added FileTemplateLoader.setEmulateCaseSensitiveFileSystem(boolean). This is handy when you are developing on Windows but will deploy to a platform with case sensitive file system. The default is false, and true is only meant for development, not for production installations. The default can be overridden by setting the org.freemarker.emulateCaseSensitiveFileSystem system property to true.

  • Bug fixed [424]: WebappTemplateLoader didn't find templates that are stored in WEB-INF/lib/*.jar/META-INF/resources. Files under that directory are visible as ServletContext resources since Servlet 3.0, yet WebappTemplateLoader has usually failed to see them because of some internal tricks.

  • Bug fixed: If a template "file" was successfully opened for reading, but then there was an IOException during reading its content, the parser (JavaCC) acted like if the template "file" was ended there, and the exception was suppressed. It's actually a JavaCC quirk that affects many other JavaCC-based languages too, but now FreeMarker has added a workaround in the Template constructor, and so now an exception will be thrown as expected.

  • Bug fixed: InvalidReferenceException.FAST_INSTANCE could accidentally store reference to an Environment instance, which hence was never garbage collected.

  • Bug fixed [426]: When setting incompatible_improvements to 2.3.22, the special variable reference .template_name in templates always returns the name of the main (topmost) template, due to an oversight in 2.3.22. Setting incompatible_improvements to 2.3.23 restores the old, backward compatible behavior. (Note that the old behavior that we emulate is itself broken, as it doesn't work well with macro calls; you should use .current_template_name or .main_template_name instead.)

  • Bug fixed [53]: Template parsing was abnormally slow for templates with very high number AST (abstract syntax tree) nodes on the same hierarchy level.

  • Bug fixed: When the template was concurrently replaced on the backing store during its first loading was still ongoing, the older version of the template could get into the cache with the time stamp of the new version, hence it wasn't reloaded after the configured update delay.

  • Bug fixed: The log_template_exceptions setting (added in 2.3.22) couldn't be set through the Configurable.setSetting(String, String) API.

  • Bug fixed: StringUtil.FTLStringLiteralEnc has escaped $ (hence generating an illegal escape) and haven't escaped { after $ and #. While this function is only used for generating error messages by FreeMarker, it's a public methods so anyone could use it.

  • Bugs fixed: Various canonical form glitches (they only affect error messages as far as FreeMarker is concerned).

Other changes

  • Modernized Manual and site design with improved functionality (always visible navigation tree, search inside the Manual, etc.), thanks to Evangelia Dendramis. (Also now the Site uses the same format and HTML generator as the Manual.)

  • Many smaller Manual and site content updates/improvements.

Notes

Changes compared to 2.3.23 RC1:

  • .current_name_name and .main_template_name is now missing (null) instead of "" if the template has no name

  • Some minor error message improvements

  • Documentation refinements