<#list> 中的 Iterable 出现 FreeMarker 错误

Posted

技术标签:

【中文标题】<#list> 中的 Iterable 出现 FreeMarker 错误【英文标题】:FreeMarker error with Iterable in <#list> 【发布时间】:2018-03-04 16:59:58 【问题描述】:

在 FreeMarker 模板中,我将一个变量传递给 &lt;#list&gt;

<#list sectorTags as sector>
     <td colspan="$sector.designatedTags!?size">$sector.name</td>
<#else>
     <td>No technology sectors defined.</td>
</#list>

但是失败了:

06:25:03,733 SEVERE freemarker.core.NonSequenceOrCollectionException: Expected a sequence or collection, but this has evaluated to an extended_hash+string (com.tinkerpop.frames.structures.FramedVertexIterable wrapped into f.e.b.StringModel):
==> sectorTags  [in template "reports/templates/techReport-punchCard.ftl" at line 105, column 32]
----
FTL stack trace ("~" means nesting-related):
    - Failed at: #list-#else-container  [in template "reports/templates/techReport-punchCard.ftl" at line 105, column 25]
----
    at freemarker.core.IteratorBlock$IterationContext.executeNestedBlockInner(IteratorBlock.java:295)
...

发生了什么事?

(如果其他人遇到这个问题,我会通过问答来解决这个问题 - 我在这里没有找到)

【问题讨论】:

【参考方案1】:

这里的问题是变量是Iterable。 FreeMarker 目前无法处理该问题(即将Iterable 转换为IteratorCollection)。

Iterable 必须明确转换为 Iterator

<#list sectorTags.iterator() as sector>
     <td colspan="$sector.designatedTags!.iterator()?size">$sector.name</td>
<#else>
     <td>No technology sectors defined.</td>
</#list>

Iteratable 没有被自动隐藏的原因在 Jira 问题(我现在找不到)中进行了讨论。如果我没记错的话,那是因为Java中有一些类型是Iterable,但不希望自动将它们变成Iterators

【讨论】:

为了以后的读者,FreeMarker确实支持直接列出Iterable-s(无需转换)。这是一个配置问题;有关更多信息,请参阅我的答案。【参考方案2】:

您需要开启Iterable 支持。为了向后兼容,默认情况下它是关闭的。您可能还应该升级 FreeMarker,因为至少在当前版本中,错误消息还包含以下内容:

提示:有问题的值是 java.lang.Iterable。使用 DefaultObjectWrapper(..., iterableSupport=true) 作为 object_wrapper FreeMarker 配置的设置应该可以解决这个问题。

其中,当您使用 Java API 配置 FreeMarker 时,看起来像这样:

DefaultObjectWrapperBuilder owb = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_26);
owb.setIterableSupport(true);
cfg.setObjectWrapper(owb.build());

【讨论】:

供参考,这里是Iterable support PR【参考方案3】:

Spring 示例

在控制器中

model.addAttribute("blogItems", blogItems);
return "main";

在模板中

<#list blogItems.iterator() as blogItem>
   $blogItem.name
</#list>

【讨论】:

以上是关于<#list> 中的 Iterable 出现 FreeMarker 错误的主要内容,如果未能解决你的问题,请参考以下文章

Java中的Iterable与Iterator详解

“Iterable<Element> 不能转换为 List<Element>” - `List` 不是 `Iterable` 的一种吗?

list() <Python 内置函数>

参数类型“List<Categories>”不能分配给参数类型“Iterable<Categories>”

Flutter List 不是“Iterable<dynamic>”类型的子类型

如何遍历两次Reduce中的Iterable<Text>values