2.3.22

Page Contents

发布日期:2015-03-01

请注意,由于 2.3.22 被设计为与以前的 2.3.x 版本完全向后兼容,因此*仅在您明确要求 2.3.22“不兼容的改进”时才激活下面描述的某些改进和修补程序(始终很明显指出),因为它们极有可能破坏现有应用程序。对于主动维护的应用程序,最好允许它们。参见如何在此处设置“无法兼容的改进”

FTL 方面的更改

  • 新的内置插件:apihas_api。如果值本身支持公开其 API,则value?api提供对value的 API(通常是 Java API)的访问,例如value?api.someJavaMethod()value?api.someBeanProperty。这意味着在需要调用对象的 Java 方法时很少使用,但是 FreeMarker 暴露给模板的值的设计简化视图将其隐藏了,并且也没有等效的内置函数。例如,当您将Map放入数据模型(并且正在使用默认的对象包装器)时,模板中的myMap.myMethod()基本上会转换为 Java 中的((Method) myMap.get("myMethod")).invoke(...),因此您不能调用myMethod。但是,如果您 RewritemyMap?api.myMethod(),则在 Java 中表示myMap.myMethod()。同样,myMap?api.myProperty在 Java 中转换为myMap.getMyProperty(),而不是myMap.get("myProperty")

如果可以,请尽可能依赖 FTL 类型和相关内置功能。只能使用?api.

对于 FTL 的[]运算符(如myMap[key])中缺少非String Map键的支持,使用?api碰巧也提供了一种解决方法,因为现在您可以编写myMap?api.get(nonStringKey)

?api默认未启用,并且并非适用于所有值。 在这里查看更多...

  • 标识符(例如someVariable)现在可以在任何位置包含减号(-),点(.)和冒号(:),但是这些字符必须以反斜杠(\)进行转义,否则将被解释为操作员。例如,要读取名称为“ data-id”的变量,正确的表达式为data\-id,因为data-id将被解释为“数据减去 id”。这也适用于命名的宏参数,当您希望在包罗万象的参数中接受任意 HTML 属性(如<@box class="someCssClass" data\-id=product.id />)时,该参数很有用。 (当您枚举宏内的所有参数名称时,获得的键字符串当然是"data-id"而不是\.)

  • 添加了?lower_abc?upper_abc。这会将123等转换为字符串"a""b""c"等(或"A""B""C"等)。达到"z"时,它会像"aa""ab"等那样 continue。这与您可以在电子表格应用程序(例如 Excel 或 Calc)的列标签中看到的逻辑相同。 More details...

  • 添加了?keep_before_last?keep_after_last。示例:"foo.bar.txt"?keep_before_last(".")返回"foo.bar""foo.bar.txt"?keep_after_last(".")返回"txt"。 (这些工作类似于?keep_before?keep_after,但是它们寻找分隔符的第一个匹配项.)

  • 在合法标识符字符集中添加了许多缺少的 UNICODE 字母和数字,例如韩 Literals 母(错误已修复: [129])

  • 错误消息质量改进:

  • 调用自定义 JSP 标记时的一些改进;稍后在各自的部分中查看它们。

    • 修正了错误:开始进行本地化查找或模板获取时,错误消息仍然引用了用于请求模板的名称,而不是实际的模板源名称(例如,在以foo.ftl的形式获取模板时,其名称为foo.ftl而不是foo_en.ftl,但是后面场景是从foo_en.ftl加载的)。

    • 现在,将更详细地说明“找不到模板”错误,并提供有关意外使用\而不是/或退出TemplateLoader的根目录的提示。

    • 当无法识别设置名称时,#setting指令会给出更有用的错误消息,并列出允许的设置名称或更正建议。

    • 遇到错误的特殊变量名称(.name)时,错误消息中将显示可用名称列表。

    • 当包装的MapMap.getMap.containsKey抛出ClassCastExceptionNullPointerException时,错误将指向引起 FTL 表达式(有一些解释),而不是冒充为低级运行时错误。

Java 方面的更改

  • 对象包装的改进:

  • DefaultObjectWrapper,仅将其incompatible_improvements设置为 2.3.22(看看这里如何...),或更准确地说,将其新的useAdaptersForContainers设置设置为true(当incompatible_improvements设置为 2.3.22 时默认为true):它不会复制Map -s ,List -s 和数组,然后将它们包装到TemplateModel -s 中(通过模板访问所有值的接口),只需将它们包装到精简的TemplateModel适配器中,这些适配器将到达所有操作的原始对象。包装的值将是新DefaultMapAdapterDefaultListAdapterDefaultArrayAdapter类的实例,而不是旧的(复制)SimpleHashSimpleSequence类。 (请注意,许多项目使用的是纯BeansWrapper而不是DefaultObjectWrapper,后者始终使用适配器方法,尽管实现方式有所不同.由于现在已修复DefaultObjectWrapper的缺点,因此始终建议使用BeansWrapper,因为BeansWrapper会给人困惑的多类型值,并且速度要慢得多.)

尽管保持尽可能向后兼容性是此更改的一个重要因素,但这是一个非常深远的更改,因此您可能需要在这里查看结果和原因...(但是,默认情况下,此更改处于活动状态,因此仅更新 FreeMarker 不会冒险现有应用程序的稳定性)

  • 添加了TemplateMethodModelEx BeansWrapper.wrap(Object object, Method method),用于包装方法而无需包装其父对象,也无需在调用时进行重载的方法选择。

  • 错误修复\ [372]:ClassCastExceptionSortedMap(通常是TreeMap)被DefaultObjectWrapper包裹后,会从中得到一个不存在的 1 个字符长的字符串。要解决此问题,如果包装的MapSortedMap且被DefaultObjectWrapper包装,则在String键得到null之后,它不会尝试退回到Character键。 (此更改应向后兼容,因为当SortedMap具有Character键时,使用String键的初始尝试会导致ClassCastException,因此,此类SortedMap -s 不能用作 FTL 哈希.)

  • 错误修复\ [368]:仅将incompatible_improvements设置为 2.3.22 或将其新的useAdaptersForContainers设置设置为true:键盘 Sequences 和“自定义” Map类型的其他行为特性不再丢失。 List -s 也一样。

  • 添加了新设置forceLegacyNonListCollections。仅当useAdaptersForContainerstrue时才重要。然后,除非将其设置为true,否则不是List -s 的java.util.Collection -s(例如Set-s)将 continue 使用SimpleSequence(即复制方法)而不是适配器方法。默认值是false,至少到incompatible_improvements 2.4.0 为止,因为SimpleSequence赋予了对这些非List -s 的索引访问权限,就像mySet[2]一样,这很奇怪,但是即使是偶然地,某些现有模板也可能会利用它。在forceLegacyNonListCollections设置为false的情况下,Set -s 等都将无法进行索引访问(?first?last也不起作用,但?size仍然可以),因此您可能想要重新测试旧模板。另一方面,您可以获得适配器方法的优点。因此,在新项目中,强烈建议将forceLegacyNonListCollections设置为false。 (适配器方法由DefaultNonListCollectionAdapter实现.)

  • 添加了新的实验性 FTL 类型的接口freemarker.template.TemplateCollectionModelEx,该接口将size()isEmpty()boolean contains(TemplateModel)方法添加到TemplateCollectionModel接口。之所以添加此功能,是因为在打包java.util.Collections时,这些额外的功能区域仍然可用,但是 FTL 到目前为止无法使用它们。虽然确切的接口详细信息被标记为实验性的,但是当将DefaultObjectWrapperforceLegacyNonListCollections属性设置为false时,?size已经使用了功能本身(请参见前面)。

  • 添加了新的实验界面freemarker.template.ObjectWrapperAndUnwrapper。这扩展了ObjectWrapper的展开功能。 BeansWrapper及其子类(如DefaultObjectWrapper)已经存在很长时间了,但并未“分解”为其他ObjectWrapper -s 可以实现的自己的已发布接口。这对于不需要BeansWrapper(或其子类)的TemplateModel实现非常有用,仅需要可解包功能的可用性。

  • 添加了新的* experimental *接口来实现?api(请参见 FTL 部分):TemplateModelWithAPISupportObjectAPIWrapperRichObjectWrapper。请注意,尽管接口是实验性的,但?api本身不是。

  • FreemarkerServlet改进:

  • FreemarkerServlet现在支持自定义 JSP EL 函数(在具有function XML 元素的 TLD-s 中定义)。此前它已经忽略了它们。可以像 Java 方法一样调用自定义 EL 函数,例如:<#assign u=JspTaglibs["/WEB-INF/utils.tld"]> ... ${u.truncate(title, 25)}

    • 错误修正:自定义标记参数的实际类型和预期类型之间存在类型不匹配时,错误消息无济于事。这是从 FTL 调用 JSP 标签库的用户经常遇到的问题(典型的“ java.lang.IllegalArgumentException:参数类型不匹配”,没有任何 FTL 上下文)。现在,这是一个适当的错误,包括解释,解决方案提示和 FTL 错误位置/引用。

    • 已解决 RFE[113][114]:FreemarkerServlet现在可以发现META-INF/**/*.tld -s 对类加载器可见,但不在WEB-INF/lib/*.jar -s 中。为了使此功能有效,必须使用MetaInfTldSources和/或ClasspathTlds FreemarkerServlet init-params 设置额外的 TLD 查找(有关这些说明,请参见FreemarkerServlet 的 Java API 文档)。例如,如果您使用嵌入式 Servlet 容器从 Eclipse 运行应用程序,因此标记库 jar-s 不在标准位置,而是像其他任何依赖项一样在 Classpath 中,那么您现在可以编写:

<init-param>
  <param-name>MetaInfTldSources</param-name>
  <param-value>classpath</param-value>
</init-param>

然后将在类加载器可见的所有META-INF目录中搜索 TLD-s。

  • MetaInfTldSourcesClasspathTlds也可以分别附加到 Java 系统属性org.freemarker.jsp.metaInfTldSourcesorg.freemarker.jsp.classpathTlds的值或由其替换。因此,可以在 Eclipse 运行配置中调整这些参数,而无需修改web.xml。 (有关详情,请参见FreemarkerServlet 的 Java API 文档。)

  • FreemarkerServlet现在可以识别org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern servlet 上下文属性,并从中将条目添加到MetaInfTldSources(上面介绍)。

  • 添加了protected FreemarkerServlet.createTaglibFactory()以允许微调TaglibFactory的设置。现在有一些设置器,例如setObjectWrappersetMetaInfTldSource等。

  • 添加了新的 servlet init-param BufferSize。如果响应状态仍然允许,则通过HTTPServletResponse.setBufferSize()设置缓冲区大小,否则忽略它。

  • TemplatePath servlet init-param 现在支持一种新的路径,看起来像classpath:com/example/myapp/templates。这类似于旧的class://com/example/myapp/templates,但是它使用初始化FreemarkerSerlvet的线程的线程上下文类加载器,因此即使freemarker.jar不在 Web 应用程序本地也可以使用。 class://具有使用FreemarkerSerlvet本身(或其子类)的定义类加载器的问题。

  • 如果incompatible_improvements设置为 2.3.22(或更高版本),则TemplatePath servlet init-param 支持在[...]内指定多个逗号分隔的路径,例如<param-value>[ WEB-INF/templates, classpath:com/example/myapp/templates ]</param-value>。这在内部创建freemarker.cache.MultiTemplateLoader

  • 添加了新的 servlet init-paramExceptionOnMissingTemplate。将此设置为true可以将未找到模板错误的行为更改为类似于其他类型的模板异常(大多数设置为 HTTP 500“内部服务器错误”响应)。如果是false(旧行为),则只会收到 HTTP 404“未找到”。尽管这也是 JSP 视图的工作方式,但事实证明这是一个问题,因为如果 MVC 视图提供 404,则某些框架也会向访问者提供 404.但是要转到转发到 MVC 视图的地步,访问者必须访问有效的 URL,只有该页面错过了它的视图,因此它在服务器端损坏了,因此应该是 500.

  • 添加了新的可覆盖方法:FreemarkerServlet.createDefaultObjectWrapper()。这可以用于通常被createObjectWrapper()覆盖的对象,但不会不情愿地禁用相关 init-params(如object_wrapper)的处理。

  • 改进的(或固定的)错误日志记录:现在,日志将始终进入 FreeMarker 自己的日志,而不仅仅是 servlet 容器日志。此外,根据 Servlet 容器的不同,有时还会丢失早期的模板未找到和模板解析错误详细信息日志。

  • 错误已修复,仅在incompatible_improvements设置为 2.3.22(或更高版本)时有效:放入 JSP * page *范围(通过#global或通过 JSP PageContext API)并在以后使用 JSP PageContext API 读回时的某种值(通常在自定义 JSP 标记中),可能会以 FreeMarker TemplateModel对象而不是标准 Java 类型的对象的形式返回。其他 Servlet 范围不受影响。某些人期望这个错误的可能性很小。受影响的值属于下面列出的 FTL 类型,要触发该错误,必须直接在模板中创建它们(例如,作为 FTLLiterals 或使用?date/time/datetime),或者您必须使用DefaultObjectWrapperSimpleObjectWrapper (或它们的子类):

  • FTL 日期/时间/日期时间值可能会以freemarker.template.SimpleDate -s 的形式返回,现在却以java.util.Date -s 的形式返回。

    • FTL 序列值可能会以SimpleSequence -s 的形式返回,现在按预期以java.util.List -s 的形式返回。这是假定object_wrapper配置设置是BeansWrapper的子类(例如DefaultObjectWrapper),但是在使用 FreeMarker 的 JSP 扩展的应用程序中实际上总是这样(否则它仍然可以工作,但这取决于ObjectWrapper的质量和功能)实施)。

    • FTL 哈希值可能以SimpleHash -es 的形式返回,现在又按预期以java.util.Map -s 的形式返回(再次,假设对象包装器是BeansWrapper的子类)。

    • FTL 集合值可能以SimpleCollection -s 的形式返回,现在又按预期以java.util.Collection -s 的形式返回(再次,假设对象包装器是BeansWrapper的子类)。

    • 错误修复:现在可以在WEB-INF/及其所有子目录中递归搜索*.tld文件。之前,它们仅在WEB-INF/WEB-INF/lib/下直接搜索。

    • 修正了错误:删除了nametag-class元素内 TLD-s 中的前导和尾随空格。

    • 纠正了不良行为:如果多个 TLD-sMap 到相同的标记库 URI,则WEB-INF/**/*.tld -s 的优先级高于来自 jar-s 或 Classpath 目录的META-INF/**/*.tld -s 的优先级。较早的情况是相反的,只是META-INF/lib/*.tld -s 仍然可以随机优先。尽管 JSP 规范(2.2)明确指出未定义 Sequences,并且不应依赖该 Sequences,但逻辑上是,如果有人将 TLD 直接放在WEB-INF下,他的意思是将其用于该特定 Web 应用程序,而不是 TLD 来自通常由多个 Web 应用程序共享的依赖项 jar。

    • 修正了错误:覆盖FreemarkerServlet.createConfiguration中设置的默认值不会再被FreemarkerServlet的出厂默认值覆盖。仅这些设置有问题:template_exception_handlerlog_template_exceptionsobject_wrappertemplate_loader

    • 修正了错误:如果在同一 servlet 上下文中有多个FreemarkerServlet -s 具有不同的配置设置,则可能导致故障。 (通常,您只有一个,就像只有一个处理*.jsp的 servlet 一样.)

    • 从 FreeMarker 工件和 XML 实体解析器中删除了所有xsd文件(web-apptaglib模式),因为在 XML 解析期间未使用它们。

    • 总体上提高了实施质量(可维护性,错误消息,性能错误修复,测试覆盖率)和更好的 API 文档。

  • 日志记录功能的改进:

  • 就像之前一样,当自动选择 Logger 库时(默认行为),FreeMarker 选择 Log4j(如果可用)。但是现在,如果结果是log4j-over-slf4j,则 FreeMarker 将直接使用 SLF4J。 (这解决了记录的位置指向 FreeMarker 的日志适配器类而不是实际呼叫位置的问题.)

    • FreeMarker 现在可以识别org.freemarker.loggerLibrary系统属性,该属性指定要使用的 Logger,例如java ... -Dorg.freemarker.loggerLibrary=SLF4J。此选项弃用Logger.selectLoggerLibrary(int),因为它固有地不可靠(因为您通常无法很好地控制类的初始化 Sequences)。系统属性的优先级高于Logger.selectLoggerLibrary

    • 总体上提高了实施质量(出现故障时会打印更多信息,等等)。

    • 新的配置设置:log_template_exceptions(Configuration.setLogTemplateExceptions(boolean))。这指定 FreeMarker 是否记录由模板处理引发的TemplateException -s。缺省值为true以实现向后兼容性,但这会导致在正确编写的应用程序中两次记录该异常,因为调用者还会记录由公共 FreeMarker API 抛出的TemplateException(即使仅作为更高级别异常的原因 exception) )。因此,在现代应用中,应将其设置为false。 (请注意,此设置对#attempt/#recover捕获的异常的记录没有影响;始终记录这些异常.)

  • Environment和自定义指令相关的改进:

  • 添加了Environment.getCurrentDirectiveCallPlace(),当从自定义指令(即TemplateDirectiveModel.execute())中调用时,该对象返回DirectiveCallPlace对象。 DirectiveCallPlace对象使您可以将任意对象与模板内的指令调用相关联,该模板可用于调用位置限制的缓存(如缩小非动态嵌套内容)。有关更多信息,请参见 Java API 文档中的DirectiveCallPlace

    • 添加了Environment.getMainTemplate()。不再使用含糊不清(并且经常损坏: [145])Environment.getTemplate()
  • Template loading:

  • 添加了新的Configuration设置template_lookup_strategy(Configuration.setTemplateLookupStrategy(TemplateLookupStrategy))。这允许自定义在请求模板时将尝试的TemplateLoader级别名称。例如,通过此方法,您可以定义自定义的本地化查找序列,而不是默认值(看起来像是foo_de_LU_MAC.ftl, foo_de_LU.ftl, foo_de.ftl, foo.ftl)。

    • 添加了新的Configuration.getTemplate(...)参数Object customLookupCondition。可以通过自定义TemplateLookupStrategy来使用此参数,以从请求的名称中推断出实际的模板名称(类似于默认查找策略基于语言环境进行的查找)。例如,在一个多域网站上,可能要定义一些专门用于域的模板,然后将域名用作自定义查找条件。然后,当请求foo.ftl时,自定义TemplateLookupStrategy可以先查找@somedomain.com/foo.ftl,然后查找@default/foo.ftl。有关更多详细信息,请参见相关Configuration.getTemplate(...)重载的 JavaDoc。请注意有关customLookupConditionhashCodeequals的要求。

    • 添加了新的Configuration设置template_name_format(Configuration.setTemplateNameFormat(TemplateNameFormat))。这允许指定 FreeMarker 使用的命名规则。目前,不允许自定义实现,您只能在TemplateNameFormat.DEFAULT_2_3_0(默认)和DEFAULT_2_4_0(推荐,至少对于新项目)中选择。 DEFAULT_2_4_0具有多个优点,但并不完全向后兼容(尽管大多数应用程序都不会受到影响)。对于典型的错误,例如使用反斜杠代替斜杠,或者退出根目录,它给出MalformedTemplateNameFormatException而不是TempalteNotFoundException。它允许方案名称仅用:而不是://(也受支持)而不是classpath:foo/bar.ftl终止。它修复了许多遗留的故障(错误),这些故障主要与.*之类的特殊步骤后对..的解释有关。请参见TemplateNameFormat.DEFAULT_2_4_0 的 Java API 文档中的差异的完整列表。

    • 现在,可以直接指定ClassLoader来创建ClassTemplateLoader,而不必指定基本Class。也就是说,现在有ClassTemplateLoader(ClassLoader, String)构造函数,还有Configuration.setClassLoaderForTemplateLoading(ClassLoader, String)方法。

    • 添加了新的 exceptionTemplateNotFoundException,现在在获取模板时将使用它代替TemplateNotFoundException。随着TemplateNotFoundException的扩展,此更改向后兼容。主要目的是解决常见的误解,即模板路径是真实文件路径。但是,新异常还有一个好处,就是它可以提供有关错误的其他 FreeMarker 特定信息,就像现在它具有getTemplateName()getCustomLookupCondition()方法一样。

    • 除了getName()之外,Template -s 现在具有getSourceName()方法。只要没有本地化的查找或获取(名称中为*)或未积极参与其他查找策略,这两个返回的结果相同。但是,当getSourceName()给出实际从TemplateLoader加载模板的名称时,而getName()返回(并且一直返回)请求模板的名称(以规范形式)。 getName()用于所有内容(如相对包含解析),但错误消息中的位置信息除外,该信息现在使用getSourceName()。而且,TemplateException现在具有getSourceName()方法。

    • Configuration.getTemplate(...)重载现在接受__ localeencoding参数,在这种情况下,它们将使用与忽略参数的重载相同的默认值。

    • 调试器 SPI 实现者,注意:DebugBreak指令现在会将模板的sourceName发送到suspendEnvironmentSpi回调,而不是其name。您还应该在registerTemplateSpi中使用sourceName,而不是name

  • Configuration:

  • 为多种设置添加了Configuration.unsetXxxisXxxExplicitlySet方法。取消设置会使其表现得好像从未调用过setXxx,因此该设置将使用适合当前incompatible_improvements值的默认值,并将在以后更改incompatible_improvements时进行调整。

    • java.util.Properties(或通常使用String-String名称/值对)配置 FreeMarker 时:
  • default设置值现在可以通过template_exception_handlertemplate_storagetemplate_loader(以及新的template_lookup_strategytemplate_name_format)设置识别,并导致Configuration.unsetXxx()被调用。

    • 错误修正:将object_wrapper设置为default(而不是未指定)时,它已忽略incompatible_improvements并始终使用ObjectWrapper.DEFAULT_WRAPPER。此修补程序仅在incompatible_improvements恰好是 2.3.21 时才有意义,因为那是将默认对象包装器从ObjectWrapper.DEFAULT_WRAPPER更改为new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build()的结果时,该结果有点不同的单例,因为它具有只读配置设置和错误修复重载方法选择规则。要使用ObjectWrapper.DEFAULT_WRAPPER而不考虑incompatible_improvements设置的值,请使用新的default_2_3_0值。

    • 修正了错误:更改localized_lookup设置的值现在会清空模板缓存,因此不会重复使用旧的查询结果。 (这仅在您在已经运行的服务下更改此设置时才有意义,这是非常不可能的.)

  • Miscellaneous:

  • 错误修复\ [145],仅在incompatible_improvements设置为 2.3.22(或更高版本)时有效:#include#nested不再将Environment的父Template(请参见Configurable.getParent())更改为包含的Template#nested“返回”到。因此,Environment的父代将始终是主要的Template。 (主要的Template是调用其processcreateProcessingEnvironment方法以启动输出生成的Template.)请注意,这仅在您直接在Template对象上设置设置时才有意义(不要与通过#setting在模板中设置设置相混淆)。修改Environment,因此不受此修复程序的影响),几乎没有人这样做。还要注意,宏调用从未将Environment父级更改为包含宏定义的Template,因此现在没有任何更改。

    • 已修复错误\ [419]:当 FreeMarker 没有读取 Java 系统属性的权限时(例如在未签名的 applet 中使用时),它不会再失败。它只是记录一些警告。

    • 由于频繁滥用,HTML_DEBUGDEBUG TemplateExceptionHandler输出现在包含警告,例如“ HTML_DEBUG 模式;在 Producing 使用 RETHROW!”。

    • 模板规范形式输出中的一些修复和改进,并因此而在 FTL 堆栈跟踪指令显示中得到了改善。

    • 将某些历史上已公开但内部 API 标记为已弃用,因此免责声明在 IDE 中更为明显。

Notes

当其不兼容的改进设置为 2.3.22 时,在DefaultObjectWrapper中为容器类型引入适配器方法的后果和原因:

  • 使用新方法(适配器方法),永远不会丢失Map -s 的键 Sequences。复制方法只能保留HashMap个子类(例如LinkedHashMap)和SortedMap -s(例如TreeMap),而不能保留更奇特的Map -s,例如 Guava 的ImmutableMap。而且,现在保留了原始Map的其他任何行为 Feature(例如,不区分大小写的键查找)。

  • 当将包装的值从模板传递回 Java 方法时,将保留Map/List的确切类型和标识。使用传统方法,Java 方法已收到特定于 FreeMarker 特定类型的MapList(充当TemplateModel的适配器)。

  • 性能 Feature 通常会有所改善,但这取决于应用程序。如果模板从数据模型读取 same(!)条目大约一次或两次(或根本不读取),这很典型,那么它们的适配器方法会提供更好的结果,否则旧版复制方法会更快(因为它可以重用之前阅读的包装条目),尽管对于大多数应用程序而言,这种减慢速度肯定不是问题。新适配器方法的性能更可预测,因为它没有初始的“尖峰”来设置容器副本(特别是对于庞大的集合而言是痛苦的),而性能却与数据模型读取的数量成线性比例(而不是与收集条目的数量)。

  • 如果将Map/List/array 换行后对其进行了更改,则更改现在将在数据模型中可见。使用复制方法时,包装的值是原始Map/List/array 的浅表快照。尽管不太可能有人故意使用此功能,但这是切换到适配器时的风险因素。

  • 从理论上讲,某些代码(主要是TemplateDirectiveModel实现)可能会错误地认为包装的Map -s 是SimpleHash -es,包装的List -s 是SimpleSequence -s 等,而不是仅仅是TemplateHashModel -s 和TemplateSequenceModel -s。这样的代码总是错误的,但是现在它确实会中断,因此这是一个风险因素。

  • 由于现在已包装原始对象的确切类型用于重载方法选择,因此选择可以有所不同(并且类似于纯BeansWrapper)。很难找到重要的案例。阵列最有可能发生更改,因为使用复制方法时,将它们解包到List -s 而不是原始数组。因为重载的方法机制可以在数组和列表之间(双向)转换,所以通常这不是问题。但是,当重载方法在数组的参数位置上具有各种类型时,它不会在不同的数组类型之间进行转换,因此这是一个风险因素。

  • SimpleHashSimpleSequence尚未被弃用。它们仍然用于在 FTL 中创建的哈希和序列,并且建议将其用于专门为从模板使用而构建的值,而不是包装已存在的MapList或数组。

  • 现在,在多线程只读访问下,暴露给多线程模板的List -s 和Map -s 在其正确操作方面承受更大的压力。这是因为适配器在从多个线程访问它们之前,不会将其内容复制到众所周知的ListMap实现(HashMapArrayList等)中。因此,这主要与自定义ListMap实现有关,它们不如标准 Java 类成熟。请注意,这始终与纯BeansWrapper相同,它被许多项目/框架(如 Struts)使用了很长时间,因此这并不是一个未知的领域。

  • 当包装的ListAbstractSequentialList(例如LinkedList)时,结果适配器将实现TemplateCollectionModel以实现更有效的枚举(#list -ing),当然除了TemplateSequenceModel之外。 TemplateCollectionModel允许 FTL 遍历列表,而无需按索引访问元素。使用旧版复制方法TemplateCollectionModel并没有实现,因为在那里不需要进行有效的枚举。

  • 迭代器(当您将它们直接放入数据模型中时)包装在DefaultIteratorAdapter而不是SimpleCollection中。这有两个结果:

  • 现在,将包装的Iterator从模板传递到 Java 方法后,可以正确地将其包装到原始 Java 对象中。

    • 包装的Iterator -s(不要与Iterable混淆)不再是线程安全的,毕竟要保留一些同步,将相同的Iterator暴露给多个并行模板执行没有多大意义。这不应该是迁移问题,因为甚至在更早的时候,这些模板执行中只有一个可以成功(未复制Iterator -s 的“内容”,因此第一次访问它的人成为了独占所有者)。所做的更改仅是早先保证了其他线程将失败(这是线程安全的),而现在没有此类保证。