Freemarker - 内置 Iterables 的行为

Freemarker - behavior of Built-ins with Iterables

我观察到 Freemarker 的奇怪行为。 我在 reportModel.affectedJars 中有一个 Iterable。它由图形数据库提供 - Tinkerpop/Titan.

${iterableHasContent(reportModel.affectedJars)?then("true", "false")}<br>
${reportModel.affectedJars?has_content?then("yes", "no")} has_content<br>
${reportModel.affectedJars?size}<br>
${reportModel.affectedJars}<br>
<#if reportModel.affectedJars?size == 0>
    <p>No archives containing CVE vulnerabilities were found.</p>
<#else>
    <#list reportModel.affectedJars.iterator() as file>
        Something...

iterableHasContent?size 的替代。 我希望这在以下方面非常一致:

false
no has_content
0
<p>No archives ...

但实际情况是:

false
yes has_content
6
--- and no iterations. ---

似乎有一些小故障让 Freemarker 认为 Iterable 不为空,但是当迭代时,它没有给出任何项目。没有抛出异常。

我正在尝试调试,但由于某种原因调试器没有在相关代码处停止。

我在 ?size?has_content 允许这种行为的范例中是否遗漏了什么?

不要尝试对 Iterable 做任何事情,除非对其调用 iterator()。问题是 FreeMarker 是在引入 Iterable 之前创建的,它把纯 Iterable(即没有实现 Collection)视为通用对象,而不是一些可列出的东西。 (在不破坏向后兼容性的情况下解决这个问题是不可能的,尽管肯定应该有一个配置选项。)这也是尺寸 6 的来源;它是散列中的项数,其中包含其方法和 JavaBean 属性。呃...

所以当你拿到Itera*tor*之后,接下来你会发现它并不支持?size。不过它支持 ?has_content。 (这假定您使用的是默认对象包装器,而不是纯粹的 BeansWrapper,这是纯粹的邪恶。)但是如果可以的话,请使用带有嵌套 #else#list。类似于:

<#list reportModel.affectedJars.iterator() as file>
    Something...
<#else>
    <p>No archives containing CVE vulnerabilities were found.</p>
</#list>

或更真实的例子:

<#list reportModel.affectedJars.iterator()>
    <p>Found some archives containing CVE vulnerabilities:</p>
    <#items as file>
       Something...
    </#items>
<#else>
    <p>No archives containing CVE vulnerabilities were found.</p>
</#list>