首页 > 解决方案 > 在数组上第 100 次使用后无法在 thymeleaf 模板中使用索引变量

问题描述

当我第 101 次尝试使用与数组索引相同的变量时(甚至在我的视图的多次渲染中),我在评估表达式时遇到了异常。我必须重新启动服务器才能再次评估表达式(直到第 101 次评估)。

<th:block th:with="array=${new String[]{'item1'}}, index=0">
    <th:block th:each="i : ${#numbers.sequence( 1, 101, 1)}">
        [[${i}]]:[[${array[index]}]]
    </th:block>
</th:block>

结果是:

1:项目 1 2:项目 1 [...] 100:项目 1 101:

例外是:

Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "array[index]" (template: "test.html" - line 10, col 13)
    at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)

Caused by: java.lang.IllegalStateException: Failed to instantiate CompiledExpression
    at org.springframework.expression.spel.standard.SpelCompiler.compile(SpelCompiler.java:111)

Caused by: java.lang.VerifyError: (class: spel/Ex3, method: getValue signature: (Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;) Expecting to find integer on stack
    at java.lang.Class.getDeclaredConstructors0(Native Method)

环境是:

这是怎么回事 ?

标签: thymeleaf

解决方案


这里的错误片段提到 Spring 正在尝试编译表达式:

SpelCompiler.compile()

而且,正如您所注意到的,当代码尝试超过 100 次数组索引访问时,问题非常具体 - 即使索引变量永远不会改变:

array[index]

有趣的是,当我对索引值进行硬编码时,我没有收到此错误 - 例如:

array[0]

我知道解决问题的两种方法:

选项1

将 SpEL 配置为不使用表达式编译。如何执行此操作取决于您的特定配置设置,但设置为:

spring.expression.compiler.mode=off

我尝试使用模式immediate和模式mixed- 但都没有奏效。只有模式off

选项 2

避免使用带有索引变量的数组 - 例如,像这样迭代列表(或数组)没有问题,其中列表包含超过 100 个对象:

<th:block th:each="i,iterStat : ${myList}">
    [[${iterStat.index}]]:[[${i}]]
</th:block>

此选项是否适合您可能取决于您的代码正在执行的更广泛的上下文。所以这可能不是一个选择。

mixed无论哪种方式,我都对编译模式不起作用感到惊讶。但是,文档确实指出,编译器可以处理的内容存在限制。

正如一个观察:我假设你想[[...]]在你的模板中使用语法,而不是更像这样的东西:

<th:block th:each="i,iterStat : ${myList}">
    <span th:text="${iterStat.index} + ':' + ${i}"></span>
</th:block>

(不过,这样做并不能避免编译问题。)


推荐阅读