spel 多层list嵌套表达式踩坑记

场景

bash 复制代码
Expression exp = spelParser.parseExpression("#{#avgTable?.get(2)?.get(0)}", new TemplateParserContext());
String _result = exp.getValue(evalContext, String.class);

当avgTable?.get(2)为空时,Method threw 'java.lang.IndexOutOfBoundsException' exception.

在 Spring Expression Language (SpEL) 中,安全导航操作符 (?.) 通常可以防止 NullPointerException,但如果它不起作用,可能是以下原因导致的:


1. ?. 无法防止 IndexOutOfBoundsException

问题原因:

  • avgTable?.get(2) 如果 avgTable 是 List 且 size() <= 2,会抛出 IndexOutOfBoundsException,而不是返回 null。
  • ?. 只能防止 NullPointerException(即 avgTable 为 null 的情况),但无法阻止越界访问。

解决方案:

  • 改用 size() 检查:

    java 复制代码
    "#{(#avgTable != null && #avgTable.size() > 2) ? #avgTable.get(2)?.get(0) : null}"
  • 或使用 SafeList 包装(自定义方法,返回 null 而不是抛异常)。


2. SpEL 版本或解析方式问题

问题原因:

  • 某些旧版本的 SpEL 可能对 ?. 支持不完全。
  • 如果使用的是 TemplateParserContext(如 #{...}),确保语法正确。

解决方案:

  • 升级 Spring 版本(推荐 Spring 5+)。

  • 检查 SpEL 表达式是否正确解析:

    java 复制代码
    Expression exp = parser.parseExpression("#{#avgTable?.get(2)?.get(0)}", new TemplateParserContext());

3. avgTable 不是标准的 Java Bean/List/Map

问题原因:

  • 如果 avgTable 是自定义类,且 get(2) 不是标准方法(如数组访问或特殊数据结构),?. 可能不会按预期工作。
  • 例如,数组访问 arr[2] 越界会直接抛异常,?. 无法阻止。

解决方案:

  • 改用 List 或 Map 结构。

  • 或手动检查索引:

    java 复制代码
    "#{(#avgTable != null && #avgTable.length > 2) ? #avgTable[2]?.property : null}"

4. 嵌套对象访问方式错误

问题原因:

  • 如果 avgTable.get(2) 返回的对象没有 get(0) 方法,?. 也无法阻止 NoSuchMethodException。

  • 例如:

    java 复制代码
    List<String> row = avgTable.get(2);  // 返回 String,但尝试调用 get(0)
    row?.get(0);  // String 没有 get(0) 方法,会抛异常

解决方案:

  • 确保对象结构正确:

    java 复制代码
    "#{#avgTable?.get(2) instanceof List ? #avgTable.get(2)?.get(0) : null}"

5. 表达式解析错误

问题原因:

  • 如果 SpEL 表达式语法错误(如括号不匹配),?. 可能不会生效。

  • 例如:

    java 复制代码
    "#{#avgTable?.get(2)?.get(0}"  // 缺少右括号

解决方案:

  • 检查表达式语法是否正确:

    java 复制代码
    "#{#avgTable?.get(2)?.get(0)}"  // 正确

推荐解决方案

1. 使用 size() 检查索引(适用于 List)

java 复制代码
Expression exp = parser.parseExpression(
    "#{(#avgTable != null && #avgTable.size() > 2) ? #avgTable.get(2)?.get(0) : null}",
    new TemplateParserContext()
);

2. 使用 Elvis 运算符提供默认值

java 复制代码
Expression exp = parser.parseExpression(
    "#{#avgTable?.get(2)?.get(0) ?: 'DEFAULT'}",
    new TemplateParserContext()
);

3. 使用 try-catch(不推荐,仅备用)

java 复制代码
Expression exp = parser.parseExpression(
    "#{T(org.springframework.util.ObjectUtils).nullSafeToString(#avgTable?.get(2)?.get(0))}",
    new TemplateParserContext()
);

总结

问题 原因 解决方案
IndexOutOfBoundsException List.get(2) 越界 检查 size()
NullPointerException avgTable 为 null 使用 ?.
自定义类无 get(0) 对象结构错误 检查类型
SpEL 语法错误 表达式不合法 修复语法
旧版 SpEL 问题 版本兼容性 升级 Spring

如果仍然有问题,建议打印 avgTable 的实际类型和结构:

java 复制代码
System.out.println("avgTable class: " + avgTable.getClass());
System.out.println("avgTable size: " + (avgTable != null ? avgTable.size() : "null"));

这样可以更精准地定位问题。

相关推荐
没差c18 小时前
winsw将jar、nginx等注册为Windows服务
windows·nginx·jar
光谱SpectrAI19 小时前
Claude Code 2.1.318 的隐私模块:4 条命令,拦了 2 条
windows
Hello_Pyhx20 小时前
NWinfo 导出 Windows 硬件信息:从 JSON 报告到缺项排查
windows·json
百事牛科技2 天前
Excel的三种密码:防看、防存、防乱改,各管各的
windows·excel
the3clipse3 天前
MPC-HC 下载安装与最佳配置教程:免费开源、轻量无广告、支持 4K 硬解的 Windows 播放器
windows·播放器·安装教程·硬件加速·mpc-hc·字幕设置·lav filters
独隅3 天前
WebStorm Windows 版 React / Next.js 实战替换指南
javascript·windows·webstorm
陈工大模型3 天前
2026年11月最新免费解压软件横评:7-Zip 、 Win解压缩名列前茅
windows·软件工程·7-zip·压缩软件
中二骚年4 天前
Windows 安全中心 / 防火墙故障,calc和Microsoft Store,终端(管理员)无法正常打开。 原因 + 修复方案
windows·安全·microsoft
万联WANFLOW4 天前
CVE-2026-98432 等漏洞自查:AI 查出的 Linux、Windows 漏洞,运维怎么确认受不受影响
linux·运维·windows·网络安全
AlanAshley4 天前
Windows 中导致延迟的软硬件及协议比重
windows