2.3.21

Page Contents

发布日期:2014-10-12

请注意,由于 2.3.21 设计为与以前的 2.3.x 版本完全向后兼容,因此*以下描述的某些改进和修复仅在您明确要求 2.3.21“不兼容的改进”时才被激活,因为它们可能,极有可能破坏现有应用程序。如果从属项目仍在积极开发中,则强烈建议允许使用 2.3.21“不兼容的改进”。参见如何在此处设置“无法兼容的改进”

请注意,我们已将专有的 BSD 样式许可证更改为 Apache 许可证,版本 2.0. 参见这里的新许可证

请注意,所需的最低 Java 版本从 1.2 增加到 1.4.

FTL 方面的更改

  • Improved ranges:

  • 已添加范围,但不包括结尾:start..<end(也可以写为start..!end)。 More...

    • 增加的长度限制范围:start..*length:例如,10..*4给出[10, 11, 12, 13]10..*-4给出[10, 9, 8, 7]10..*0给出[]。当使用这些范围进行切片时,如果在达到指定范围长度之前已到达切片序列或字符串的末尾,则切片将无错误结束。因此,例如,要从字符串s中获取前 10 个字符,或者如果s短于 10 个字符则少一些,则可以使用s[0..*10]More...

    • 方括号现在可以接受任何来源的范围值,例如<#assign r = 1..3> ${'foobar'[r]}将显示"oob"。之前,它仅支持直接在方括号内指定的范围,例如'foobar'[1..3]

    • 现在,对具有无界范围的序列进行切片时,现在允许其范围起始索引比切片后的序列的最后一个索引高一个。例如,['x', 'y'][2..]不再是错误,而是空序列。 (当然['x', 'y'][3..]仍然是错误.)

    • someString?substring(from, toExclusive)someString?substring(from)现在已弃用;请使用以下切片表达式:someString[from..<toExclusive]someString[from..]。如果正在处理 XML,则发出警告:由于切片表达式同时适用于序列和字符串,并且 FTL 中的 XML 节点通常同时同时属于序列和字符串,因此等效表达式为someXmlNode?string[from..<toExclusive]exp?string[from..],因为如果没有?string,它将进行切片节点序列而不是节点的文本值。

    • 如果将 FreeMarker 配置中的incompatible_improvements设置为至少 2.3.21,则右无界范围变得可读(如#list -able)。以前,它们只能用于切片,否则表现得像空序列。

  • 新内置的?url_path:与内置 URL相同,只是它不会转义斜杠(/)字符。这意味着用于将使用斜杠(而不是反斜杠!)的路径(例如来自 OS 或某些内容存储库的路径)转换为可以插入 URL 的路径部分的路径。

  • 用于字符串操作的新内置函数:

  • someString?keep_before(substring[, flags]) : More...

    • someString?keep_after(substring[, flags]) : More...

    • someString?remove_beginning(substring) : More...

    • someString?remove_ending(substring) : More...

    • someString?ensure_starts_with(substring[, substitution[, flags]]) : More...

    • someString?ensure_ends_with(substring) : More...

  • someString?number现在可以识别所有 XML 模式编号格式,例如NaNINF-INF以及 Java 本地格式Infinity-Infinity

  • 如果 FreeMarker 配置中的incompatible_improvements至少设置为 2.3.21,则someNumber?c将分别针对正/负无穷大和 IEEE 浮点非数字返回"INF""-INF""NaN"。这些是这些特殊值的 XML Schema 兼容表示。早先它返回了java.text.DecimalFormat在美国语言环境中所做的事情,任何(通用)计算机语言都无法理解。

  • 新内置的:someString?boolean。例如,这对于将来自 XML 的“ true”和“ false”字符串转换为真实布尔值很有用。 More...

  • 日期/时间/日期时间相关更改:

  • 添加了新的date_format/datetime_format/time_format设置值:以"xs"开头的 XML 模式格式和以"iso"开头的 ISO 8601:2004 格式。格式字符串可以使用各种空格(或_)分隔的选项 continue,例如hmsms用于设置显示的精度,nzfz用于设置时区偏移的可见性,ufu用于使用 UTC 时区。例如,要使用具有分钟精度的 ISO 8601 且未显示区域偏移,请将datetime_format设置设置为"iso m nz",这样输出将类似于2014-09-03T20:56More...

    • 因为?string?date/?time/?datetime内置插件也可以使用date_format/datetime_format/time_format设置值,所以可以使用someDate?string.xssomeString?date.xs之类的新格式。 (对于"xs""iso"格式,可以使用_代替空格,这意味着,例如,您可以编写lastModified?string.iso_m_u而不是更详细的lastModified?string["iso m u"].)

    • 现在"iso""xs"可能是date_format/datetime_format/time_format设置值,这也意味着现在也可以通过?date/?time/?datetime解析这些值。主要应用程序是处理 XML DOM,因为值以字符串形式传入,现在您可以执行order.confirmDate?date.xs之类的操作将其转换为实际日期。

    • 现在不推荐使用?iso_... built-ins,而推荐使用上述新的设置值。可以将它们设置为默认日期/时间/日期时间格式,与格式体系结构无缝配合(因此也可以解析字符串),并具有更多/更好的选项(ms始终显示 3 毫秒数字,fz强制显示时间区域偏移)。

    • 如果“不兼容的改进”配置设置至少为 2.3.21,则?iso_...内置插件将不再显示java.sql.Time值的时区偏移。大多数数据库存储的时间值不在任何时区中,而仅存储时,分,秒和十进制秒字段值,因此显示时区没有任何意义。 (值得注意的 exception 是 PostgreSQL“带时区的时间”列,其中可以使用mzTime?string.iso_fz.)

    • 添加了?is_time?is_datetime?is_date_only(应称为?is_date,但是已经被使用)和?is_unknown_date_like来检查类似日期的值的确切类型。

    • ?is_date现在已弃用,请改用?is_date_like。这是因为?is_date听起来像在检查该值是否为不带时间部分的日期,但实际上它还会为时间,日期时间和未知的类似日期的值返回true

    • 添加了?date_if_unknown?time_if_unknown?datetime_if_unknown内置函数,它们使用一些子类型标记类似日期的值:分别为不带时间的日期,时间或日期时间。但是,如果该值已包含此信息,则内置无效。也就是说,它将永远不会转换值的子类型,仅在未知时才添加子类型。

    • 已修复的错误:ISO 8601 日期(通过?iso_..."iso"格式设置)现在使用的是 1582 年之前的公历,而不是儒略历。该标准(间接)是必需的,这也是默认的 Sun/Oracle Java XML Schema date/time/dateTime 解析器的工作方式。

  • 错误消息质量改进(针对频繁的支持请求和一些错误消息错误):

  • 修复了当错误位于嵌套块内时,如果#if具有#else#elseif,则#if/#else/#elseif不会隐藏在 FTL 堆栈跟踪中的故障。

    • 未定义的变量异常错误消息中的一些新的上下文相关提示。

    • 修复了文件末尾的未关闭指令错误消息,该错误消息报告了错误的未关闭指令名称

    • 访问 XML 数据时更好地键入错误消息(用freemarker.ext.dom包裹时适用):

  • 尝试在期望标量值的地方使用node.noSuchChildNodes将说明问题是您在构造 XML 查询中没有匹配项。

    • 尝试在期望标量值的地方使用node.multipleSuchChildNodes将说明问题是在构造 XML 查询中存在多个匹配项。

    • 尝试使用node.exactlyOneChildNode作为数字,日期/时间/日期时间或布尔值将说明来自 XML 的值始终是字符串(文本),并且必须通过?number?boolean?date.xs等进行显式转换。

    • 在不希望使用方法值的地方尝试使用obj.someMethod而不使用()会建议调用该方法。

    • 在不希望使用方法值的地方尝试使用类似obj.getFooobj.isFoo而不使用()的方法,建议使用obj.foo格式。

    • 现在,在不遵守换行符的环境中呈现消息时,消息的可读性大大提高。 (这通常发生在未正确实现的 HTML 错误页面和日志查看器中.)

    • 更好的 FTL 指令堆栈跟踪:

  • 错误消息现在最多包含 10 行 FTL 堆栈跟踪(除非它在完整的 FTL 堆栈跟踪的顶部),因为当异常是 Java 堆栈跟踪中的原因异常时,根本不打印 FTL 堆栈跟踪,或仅打印getMessage()值而不是堆栈跟踪时。

    • 现在,由于 FTL 堆栈跟踪包含更多的文本标签,因此更易于说明。

    • 现在,属于嵌套的堆栈框架被标记为不同,否则,当堆栈跟踪不适合错误消息时,将被过滤掉。

    • 已修复的错误:?substring引发了低级java.lang.IndexOutOfBoundsException -s 而不是具有 FTL 堆栈跟踪的更具描述性的TemplateModelException -s。

    • 修正了错误:有时使用 FTL 堆栈跟踪对范围进行切片时会抛出低级java.lang.IndexOutOfBoundsException -s 而不是更具描述性的TemplateModelException -s。

    • 错误修复了\ [402]:修复了将没有其必需参数的调用指令(例如<#list>)报告为未知指令时误导解析器的错误消息。

    • 错误修复\ [222]:当someString[someIndex]失败且字符串索引超出范围时,质量错误消息。

    • 错误修复\ [27]:当#import-解析失败的模板时,质量不是很好。

  • 新的include指令选项ignore_missing=boolean。如果将此设置为true,并且缺少要包含的模板,则错误将被忽略,并且不包含任何内容。

  • setting指令现在可以设置output_encoding设置。

  • 新的特殊变量:.locale_object。类似于.locale,只是它是java.util.Locale对象,而不是字符串。如果要将当前语言环境传递给 Java 方法,这很方便。

  • 如果 FreeMarker 配置中的incompatible_improvements至少设置为 2.3.21,则重复键的哈希* literal *现在仅使用?keys拥有一次密钥,并且仅使用?values拥有与该密钥关联的最后一个值。这与hash[key]的行为以及 Java 中的 Map 工作方式一致。

  • 修正了错误:?is_enumerable返回true以便从 Java 对象获取 Java 方法,尽管这些值不是<#list ...>可用的。 (这实际上是BeansWrapper的历史古怪,而不是?is_enumerable中的错误,但现在?is_enumerable意识到了这种 exceptions.)

  • 错误修复\ [257]:?matches的结果值不是“可重入”。例如,您无法在另一个列表中列出匹配项,而在这些列表中您还列出了完全相同的结果值(存储在一个公共变量中),因为它们将从同一迭代器中消耗。最重要的是,即使访问相同结果值的?size也会终止相同值的外部列表。

  • 错误修复\ [229]:如果将incompatible_improvements设置为 2.3.21(或更高),则未封闭的 Comments(<#-- ...)和#noparse -s 不会在模板末尾被静默关闭,而是会导致解析错误。

Java 方面的更改

  • 添加了新的Configuration构造函数Configuration(Version incompatibleImprovements)。这不赞成模糊的Configuration()构造函数,并且在大多数情况下不需要使用setIncompatibleImprovements(Version)。查看示例here...

  • incompatible_improvements设置(如上述构造函数)设置为 2.3.21 时,两个设置默认值会更改:

  • object_wrapper设置(Configuration.getObjectWrapper())的默认值从ObjectWrapper.DEFAULT_WRAPPER更改为另一个几乎相同的DefaultObjectWrapper单例,由new DefaultObjectWrapperBuilder(Version).build()返回。新的默认对象包装器的“不兼容的改进”版本设置为与Configuration相同。 (有关BeansWrapperDefaultObjectWrapper的 2.3.21“不兼容的改进”,请参阅下文)。此外,新的默认对象包装器不允许更改其设置; setter 方法将抛出IllegalStateException。 (如果有任何尝试在您的应用程序中使用旧默认值调用 setter 的方法,那将是一个危险的错误,该错误现在不会一直隐藏.由于旧默认值也是单例,可能由独立开发的组件共享,因此大多数人希望使用- (并且其他必然是错误的)。此外,由于单例在发布后被修改,因此可能会发生并发故障(甚至污染类自省缓存)。

    • template_loader设置(Configuration.getTemplateLoader()}的默认设置更改为null,这意味着 FreeMarker 将找不到任何模板。之前的默认值是FileTemplateLoader,该目录使用当前目录作为根目录。这是危险且脆弱的,因为您通常无法很好地控制当前目录。幸运的是,旧的默认值几乎从未在正确的位置寻找模板,因此几乎所有应用程序都必须设置template_loader,因此更改默认值不太可能破坏您的应用程序。
  • 新的BeansWrapperDefaultObjectWrapperSimpleObjectWrapper构造函数采用Version incompatibleImprovements参数。它与Configurationincompatible_improvements设置具有相同的作用,但它适用于ObjectWrapper。 (由于ObjectWrapper -s 通常在多个Configuration -s 之间共享,因此它们不能使用Configuration的设置.)在新的或开发中的项目中,建议现在使用Configuration.VERSION_2_3_21。现在不建议使用不带Version参数的构造函数。

  • Management 可能由独立开发的子系统共享的DefaultObjectWrapper -s 和BeansWrapper -s 单例的更安全,内存效率更高的方法:

  • 从现在开始,您应该使用new DefaultObjectWrapperBuilder(version).build()new BeansWrapperBuilder(version).build()而不是new DefaultObjectWrapper(...)new BeansWrapper(...)。 (构建器对象具有类似于BeansWrapper has 的属性(配置设置),用于指定创建的对象的属性。)创建的对象是单个(VM 范围,或至少是 Web 应用程序范围)和只读(表示不可配置,因此可以安全共享)。使用这些工厂而不是创建新实例的主要好处是,它允许 FreeMarker 在返回的实例之间共享类自省缓存(BeansWrapper -s/DefaultObjectWrapper -s 的内部部分,填充起来很昂贵)。这允许在彼此不知道并在内部使用 FreeMarker 的组件之间共享缓存(和对象包装器)。

    • 弃用静态字段ObjectWrapper.DEFAULT_WRAPPERBEANS_WRAPPERSIMPLE_WRAPPER,因为这些ObjectWrapper -s 是可配置的(不是只读的),因此用作单例很危险(行为不佳的第三方组件会把它们弄乱)。请改用上述工厂。它们也更加灵活,因为您可以为它们和其他BeansWrapper设置指定所需的不兼容改进版本。

    • 不推荐使用不带ObjectWrapper参数的所有SimpleHashSimpleCollectionSimpleSequence构造函数,因为它们通常使用ObjectWrapper.DEFAULT_WRAPPER作为默认值,而它们本身已被弃用。

    • BeansWrapperDefaultObjectWrapperSimpleObjectWrapper现在实现了freemarker.template.utility.WriteProtectable接口,通过调用writeProtect()可以将对象包装器的配置属性永久设置为只读。尝试在这样的ObjectWrapper上调用二传手将立即导致IllegalStateException。 (这也是getInstance方法返回的单例的用法;请参见前面的内容)。

  • 使用String(在java.util.Properties对象中或通过<#setting ...>)指定time_zone设置的值时,现在可以将其设置为"JVM default",以使用 JVM 默认时区。无论如何,JVM 默认值是该设置的默认值,但是现在您可以显式声明该值,或者如果此值先前已被覆盖,则可以恢复该值。

  • 添加了新的配置设置sql_date_and_time_time_zone(Configurable.setSQLDateAndTimeTimeZone(TimeZone))。如果将其设置为非null,则处理java.sql.Datejava.sql.Time值时使用的时区将是该时区,而不是time_zone FreeMarker 配置设置的值。这很有用,因为 JDBC 通常会构造 Java Date对象,以便使用 JVM 默认时区呈现它们时,它们将“按原样”显示数据库中的年,月,日和时分秒值。由于仅 SQL 日期和仅 SQL 时间值的时区转换没有多大意义(与 SQL 时间戳不同),因此您应该将此设置设置为 JVM 默认时区(TimeZone.getDefault(),或者通过java.util.Properties配置 FreeMarker ,作为属性值“ JVM default”)。为了向后兼容,默认值为null。有关更多详细信息,请参见Configurable.setSQLDateAndTimeTimeZone(TimeZone)的 JavaDoc。

  • 当使用java.util.Properties配置 FreeMarker(通常是将配置存储在.properties文件中)时,对于可以指定完全限定的类名的设置(最著名的是object_wrapper设置),现在还可以指定构造函数参数和 JavaBean 属性分配。例如,现在您可以编写与此 Java 代码obj = new com.example.MyObjectWrapper(1, 2); obj.setExposeFields(true); obj.setCacheSize(5000); object_wrapper = obj;几乎等效的object_wrapper=com.example.MyObjectWrapper(1, 2, exposeFields=true, cacheSize=5000)。如果您使用的是这种新语法(即,如果类名后面有括号,即使它们为空),并且该类有一个生成器类,则该类将被自动使用。例如,object_wrapper=DefaultObjectWrapper(2.3.21)将创建一个DefaultObjectWrapperBuilder来构建最终实例,因此对象包装器将是单例而不是新实例。如果参数和属性分配为 0,则新语法还将查找公共静态INSTANCE字段。有关更多详细信息,请参见Configuration.setSetting的 Java API 文档。

  • 找不到模板的 exception 现在说明了模板加载器解释了模板路径,并显示了TemplateLoadertoString。现成的TemplateLoader实现现在具有覆盖的toString来显示实际的基本目录和此类详细信息。鼓励自定义TemplateLoader实现覆盖toString

  • 添加了Configuration.setSharedVariables(Map/*<String, Object>*/),用于设置 Spring IoC 和其他 IoC 解决方案的共享变量。已经存在的Configuration.setSharedVariable(String, Object)不是 JavaBean 属性,因此很难使用它。此外,Configuration.setObjectWrapperConfiguration.setSharedVariables的调用 Sequences 并不复杂(与Configuration.setSharedVariable的情况不同),这在大多数 IoC 解决方案中都是必不可少的。

  • 主要涉及工具(如 IDE 插件)的作者:

  • ParseException -s 现在还存储错误的结束位置,而不仅仅是错误的开始位置。如果要在源代码中强调错误,而不仅仅是指出错误,这将很有用。

    • Configuration.getSupportedBuiltInDirectiveNames()可用于返回 FreeMarker 支持的指令名称。

    • TemplateExceptions现在类似于ParseException -s 公开错误的位置(模板名称,行,列,结束行,结束列)。在适用的情况下,它们还以规范的 FTL 源格式公开归咎于表达式;这对InvalidReferenceException -s 最有用。

  • 在 Java 5 和更高版本中,重载方法查找(从缓存)的并发性能得到了改善。

  • Version实例是“不兼容的改进”断点,现在可以通过诸如Configuration.VERSION_2_3_21的常量获得。

  • 从现在开始,如果您尝试将“不兼容的改进”设置为大于当前 FreeMarker 版本或小于 2.3.0,则将引发IllegalArgumentException。因此,new Configuration(someVersion)不仅会激活该版本的修复程序,而且还会确保该应用程序不会在具有较旧 FreeMarker 版本的环境中运行。 (在较旧的 FreeMarker 版本上,您所要求的改进尚未实现,因此您应该获得 exception.)

  • 添加了新的配置设置show_error_tips,默认为true。设置是否应在模板处理过程中出现的错误的错误消息中显示提示。

  • 现在,您可以使用BeansWrapper.setMethodAppearanceFineTuner(MethodAppearanceFineTuner)而不是覆盖BeansWrapper.finetuneMethodAppearance(现已弃用),因此您无需扩展对象包装器类即可自定义此方面。

  • 添加了Configuration.getCoreDirecticeNames(),它返回 FreeMarker 提供的所有指令的名称。这对于 IDE-s 很有用。

  • template_loader已添加为可能的配置设置Properties键。

  • 现在,标准的CacheStorage实现具有用于监视缓存大小的getSize()方法。 MruCacheStorage也具有getSoftSize()getStrongSize()

  • 配置设置错误消息中的各种较小改进。

  • 仅使用不兼容的改进 2.3.21:空范围返回Constants.EMPTY_SEQUENCE而不是空SimpleSequence。从理论上讲这是向后兼容的,因为 API 仅承诺提供实现TemplateSequenceModel的东西。

  • FreeMarker 现在要求 Java 版本已从 1.2 更改为 1.4.

  • 修正了错误,并改进了重载方法的选择/调用,但仅当您使用构造函数参数Configuration.VERSION_2_3_21创建BeansWrapper/DefaultObjectWrapper时(或者如果您使用Properties来配置 FreeMarker,您可以像object_wrapper=BeansWrapper(2.3.21)那样进行操作),或者如果您使用Configuration类似的incompatible_improvements 2.3.21 并且object_wrapper设置保留为默认值。由于这些变化,极有可能会选择与以前不同的重载方法,或者甚至在较早的情况下会出现歧义错误(尽管相反的情况更为频繁),因此修复不会自动进行 Active。但是,该修复程序大多数情况下只会影响失败的调用,或者较早选择了错误的方法,因此建议为仍在积极开发的项目激活它。此修复程序包括许多更改:

  • 以前,null参数值仅具有匹配的重载方法,其中相应的参数具有Object类型,而不是其子类。这显然是一个错误。现在,它考虑了参数类型为非原始的所有重载,并且像 Java 语言一样,它选择了其中具有最特定类型的重载。这是最重要的解决方案,也是向后兼容性方面最具风险的解决方案。就像您在 Java 类中具有m(Object o)m(String s)一样,在模板中较早地进行m(null)调用时,它已选择m(Object o),但现在它将选择m(String s)(因为String也是null-且比Object更具体)。此外,如果您在同一个类中也有m(File f),则现在将引起歧义异常,因为无法比较FileString的特异性(与 Java 语言下的规则相同),而以前这不是问题仅m(Object o)被视为适用。

    • 大量重载了带有重载方法选择的数字的行为:
  • 如果可能的话,现在总是选择重载,以避免溢出和截断为整数(例如 1.5 到 1)。在没有发生此类严重损失的方法中,它选择精度损失风险最小的重载(除非其他优先级更高的条件建议否则)。早些时候,方法选择容易导致溢出或精度损失,特别是当参数是带小数的 Literals 时。

    • 重载的方法调用现在可以转换为非原始数字类型,例如,如果参数类型为Integer,则Bytebyte值会自动转换为Integer。 (这始终适用于非重载方法.)在需要进行这种转换的地方,以前认为该方法不适用。

    • 现在,方法选择不仅基于包装数字的类型,还基于其值。例如,现在将值1Long视为与参数类型为intshortbyte的方法兼容,因为1可以无损失地存储在其中。这很重要,因为与 Java 语言不同,在 FTL 中,您对数字类型(实际上是包装数字的类型)没有严格的控制,因为 FTL 没有类型声明。 (如果有多种兼容方法,它将仍然尝试选择具有相同或更大数值类型的方法.)

    • 现在支持往返BigInteger的转换。

    • 现在,方法选择歧义错误的发生频率要低得多。通过选择兼容的方法,然后选择其中一种参数类型最具体的方法,可以解决歧义问题。更改为:

  • 在比较两个参数列表的整体特异性时:较早的参数列表被认为是更具体的,是具有某些参数在特异性上获胜的参数列表;如果两个参数都具有这样的参数,那就是模棱两可。现在,如果一个方法具有比其他方法更匹配的参数,或者两个方法仍然相等(如果它具有第一个更好的匹配参数),则此方法就足够了。这可能会导致选择似乎是任意的(但仍是确定性的),但是由于没有自动的方法来发现模板中的方法选择歧义(与 Java 源代码不同,在编译过程中会发现它们),特别是因为重载选择必须依赖于值的运行时类型,这甚至会使适当的测试变得困难,这被认为是比在方法的选择不明显时引发异常更好的折衷方案。还要注意,实际上,这种机制比仅计算每种方法的“获胜者”参数位置更为复杂,因为某些类型的获胜比其他任何一种都更强大:在另一种可能冒着大量尾数精度损失风险的情况下,获胜是最强(例如舍弃小数而不是不保留),则胜出,而原始类型胜过盒装类的弱者(如intInteger),子类获胜(例如StringObject)介于这两者之间。

    • 在同一参数位置比较两个参数类型的特异性时:该算法现在认为原始类型比其对应的装箱类更具体(例如int被认为比Integer更具体)。

    • 使用不同参数计数的重载 varargs 方法存在一个错误,该错误有时会忽略比较方法的最后一个参数,这消除了潜在的决定因素,因此可能导致歧义错误。是否发生这种情况取决于 Java 反射 API 返回这些方法的 Sequences,该 Sequences 是无证的,并且至少在某些 Java 更新后会改变,从而破坏了应用程序。

    • 在比较两种数组类型的特异性时,到目前为止,它们被视为相等。现在比较组件类型,然后选择具有较少特定组件类型的组件。例如,在f(String[])f(Object[])中,最后一个将始终获胜。这听起来可能有争议,但是由于我们无法有效地区分序列或List中所有项目的通用类型,因此我们不知道两个数组是否确实是有效目标,因此我们选择了最安全的选择。

    • 如果存在多个具有相同数量参数但数组参数位置类型不同的重载方法,则认为 FTL 序列值(如 Java List -s 或 FTL [x, y, ...]常量)不适用于具有数组类型的参数。也就是说,如果 Java 中有f(String[])f(String),则模板中的f(['foo', 'bar'])报告没有兼容的重载。现在它将选择f(String[])。请注意,如果还有f(List)甚至是f(Collection),它将优先使用那些而不是数组。 (为了保持一致性,即使参数是直接来自 Java 的List(而不是在 FTL 内部创建),即在将其包装然后解包到原始List对象时,该转换也将起作用。)对于多维数组参数类型,此转换将以递归方式工作,因此您可以传递序列号作为参数。

    • 如果存在多个具有相同数量参数但类型不同的重载方法,则包装 Java 数组的 FTL 序列值(当 FreeMarker 也通过AdapterTemplateModelWrapperTemplateModel意识到时)不被认为适用于List类型的参数。数组参数的位置。因此,这非常类似于上一点中描述的问题,但是是将数组转换为List。尽可能避免将数组转换为List,但如果没有其他选择,将尝试使用该数组。请注意,与List到数组的转换不同,FreeMarker 在这里无法处理多维列表,也就是说,数组数组不会转换为List -of_List -s。

    • FTL 字符串到 Java char/Character的转换现在适用于重载的方法参数;早期它仅适用于非重载方法。如果字符串长度为 1,它将被视为与charCharacter类型的参数兼容。

    • 展开多类型 FTL 值时,减少选择错误的目标 Java 类型的机会:当展开实现多种 FTL 类型(例如,字符串和哈希)但未实现AdapterTemplateModelWrapperTemplateModel的参数值时,必须确定是否将该值解包到哪种 Java 类型(例如StringMap)。在较早的版本中,该决定是基于给定参数位置的参数类型的最特定的通用超级类型做出的。但是,常见的超级类型过于通用,通常为Object。现在BeansWrapper为重载方法的每个参数位置存储“类型标志”,从中可以判断给定参数位置上的任何重载中是否存在潜在的目标 Java 类型。

    • 在许多情况下,与在所应用提示生成算法的限制范围内可能使用的提示类相比,用于包装的提示类较少。 (当关于如何从 FTL 值创建 Java 对象时存在歧义时,展开提示会产生影响.在大多数情况下,过于通用的提示无效.)(这是一个高度技术性的 Topic.它的方式可行的方法是,为具有相同数量参数的重载所共享的给定参数位置选择一个通用的可解开提示类,并且该提示类必须尽可能具体,同时它必须适合所有这些参数类型.具有过于笼统的提示的实例有以下几种:(a)搜索两个相同位置参数类型的最特定的通用类/接口时,如果有多个没有关系的通用类/接口(这始终最多是一个类和一个或多个不相关的接口),由于含糊不清,它可以回想起使用Object作为解包提示。现在,在这种情况下,如果其中有非Object类,它将被选作提示(即,我们忽略了共同的界面 ces)。否则,如果通过删除CloneableSerializableComparable(按此 Sequences)仅剩下一个接口,则将选择该接口。只有这样,它才降为Object。 (b)基本类型的最常见的通用类和相应的拳击类有时是Object而不是拳击类。这取决于 Java 方法的内部 Sequences,因此非常不可预测,例如在应用程序下升级 Java 之后结果可能会改变。 (c)数字原始值和数字非原始值的公共超类始终为Object,如果它们是原始拳击类对,则为拳击类,否则为Number。 (d)如果在所有重载的 varargs 方法中 varags 参数的位置都不相同,则有时某些 varargs 参数未使用过于通用的提示进行包装。发生这种情况是不可预测的,因为它再次取决于 Java 内部方法的 Sequences。)

    • 在调用 Java 方法之前展开方法调用参数的包装时,如果参数是AdapterTemplateModel并且目标参数类型是原始类型,则AdapterTemplateModel.getAdaptedObject(Class hint)已收到目标参数的原始类型(例如int而不是Integer)作为提示。这没有意义,因为getAdaptedObject仅返回Object -s,而不返回原始值。但是,BeansWrapper期望返回的值是原始类型,否则它已将其丢弃。 WrapperTemplateModel发生完全相同的问题。因此,最终,如果目标参数类型是原始参数,并且实现了其中一些接口,则它们的返回值将始终被丢弃,并且 FreeMarker 会回到其他解包方式。现在BeansWrapper始终会传入,并希望使用拳击类型(如Integer)而不是原始类型。

  • 错误修复\ [373]:实际上是三个错误,由于<#ftl encoding="...">的字符集覆盖,当 FreeMarker 重新加载模板时,可能会引起问题:首先,如果模板加载器是URLTemplateLoader,则第二次调用TemplateLoader.getReader()时,并且第一次返回的Reader已被使用,它可能会返回一个空的或损坏的模板,具体取决于后备 URL 的实现。其次,当 FreeMarer 因为用<#ftl encoding="...">指定的编码不同于首先用于加载模板的编码而决定是否必须重新加载模板文件时,它使用了区分大小写的比较,因此经常不必要地重新加载(例如“ UTF-8”和“ utf-8”表示相同)。现在,此比较不区分大小写。最后,在重试第二个字符集时,TemplateCache忘记关闭第一个Reader,这可能是句柄泄漏。

  • 错误修复\ [411]:OSGiBinding 清单中的无效和冗余执行环境名称已删除。现在看起来像这样:Bundle-RequiredExecutionEnvironment: J2SE-1.5, J2SE-1.4。也就是说,我们更喜欢(并根据其编译)1.5,但仅需要 1.4.

  • 错误修复\ [409]:当获取存在但 Map 到null的 length-1 String密钥时,以不安全的方式同时修改了SimpleHash的内部Map。此操作将意外地向内部 Map 添加Character键,这不是线程安全的操作。

  • 已修复错误\ [273]:使用java.net.URLConnection -s 的TemplateLoader -s 应该将URLConnection.useCaches设置为false,否则它将无法检测到某些配置上的模板缓存。

  • URLTemplateLoader及其子类和WebApplicationTemplateLoader现在具有setURLConnectionUsesCaches(Boolean)方法。建议将此属性从默认的向后兼容值null设置为false。由于 FreeMarker 具有自己的模板缓存和自己的更新延迟设置(template_update_delayConfiguration.setTemplateUpdateDelay(int)),因此不会造成性能问题。 null值会将java.net.URLConnection的缓存保留为默认值,通常为true

    • 如果incompatible_improvements设置为 2.3.21(或更高版本),并且模板是通过Configuration.getTemplate加载的,并且使用中的TemplateLoadernull上还剩下URLConnectionUsesCaches,则其行为就像设置为false一样。请注意,仅当通过Configuration.getTemplate(或TemplateCache)加载模板时,此incompatible_improvements技巧才有效。
  • 已修复的错误:更改影响类自省结果的DefaultObjectWrapperBeansWrapper的属性(如exposureLevelexposeFields)时,自省缓存未清除,因此返回了在更改这些属性之前已自省的类的陈旧信息。现在,更改此类属性将始终清除自省缓存。

  • 错误修正:用于空序列,空哈希,空集合和空迭代器的常量不是Serializable

  • 已修复错误[300]:Logger 类可用性检查不正确,因为它已使用线程上下文类加载器检查了 Logger 库的可用性,然后稍后尝试使用 FreeMarker 类的定义类加载器链接到它们。使用某些类加载器设置(有时在 Netbeans 下尤其如此),这导致ClassDefNotFoundError -s 使 FreeMarker 无法使用。 (支票本身也不是很耐用,因为它没想到LinakeError -s,只有ClassNotFoundException.)

  • 已修复的错误:ClassUtil.forName,在 FreeMarker 中广泛用于将类名称解析为类,如果线程上下文类加载器为null,则不再尝试在使用 FreeMarker 的定义类加载器加载之前尝试使用引导类加载器进行加载。

  • 错误修复\ [311]:TemplateBooleanModel.TRUEFALSE现在可序列化

  • 已修复的错误:Version类中的各种问题,例如hashCode错误,可能的并发故障以及接受了一些格式错误的版本字符串。

  • 已修复错误\ [414]:如果 JRebel 不可用,则在 FreeMarker 静态初始化 JRebel 可用性期间暂停 Eclipse 调试模式的运行。

Other changes

  • 该许可证已从我们专有的 BSD-Style 许可证更改为众所周知的“ Apache 许可证,版本 2.0”。此外,版权所有者已经从“ Visigoth Software Society”(由 Jonathan Revusky 创立)变为三个主要的 FreeMarker 2 开发人员/贡献者“ Attila Szegedi,Daniel Dekany 和 Jonathan Revusky”。参见这里的新许可证

  • 所需的最低 Java 版本从 1.2 提高到 1.4. FreeMarker 不适用于 Java 1.2 或 1.3.

  • 《手册》和《 API JavaDocs》中的许多较小的改进和修复。