当前位置: 首页 > ds >正文

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

场景

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) 如果 avgTableListsize() <= 2,会抛出 IndexOutOfBoundsException,而不是返回 null
  • ?. 只能防止 NullPointerException(即 avgTablenull 的情况),但无法阻止越界访问。

解决方案:

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

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

问题原因:

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

解决方案:

  • 升级 Spring 版本(推荐 Spring 5+)。
  • 检查 SpEL 表达式是否正确解析:
    Expression exp = parser.parseExpression("#{#avgTable?.get(2)?.get(0)}", new TemplateParserContext());
    

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

问题原因:

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

解决方案:

  • 改用 ListMap 结构。
  • 或手动检查索引:
    "#{(#avgTable != null && #avgTable.length > 2) ? #avgTable[2]?.property : null}"
    

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

问题原因:

  • 如果 avgTable.get(2) 返回的对象没有 get(0) 方法,?. 也无法阻止 NoSuchMethodException
  • 例如:
    List<String> row = avgTable.get(2);  // 返回 String,但尝试调用 get(0)
    row?.get(0);  // String 没有 get(0) 方法,会抛异常
    

解决方案:

  • 确保对象结构正确:
    "#{#avgTable?.get(2) instanceof List ? #avgTable.get(2)?.get(0) : null}"
    

5. 表达式解析错误

问题原因:

  • 如果 SpEL 表达式语法错误(如括号不匹配),?. 可能不会生效。
  • 例如:
    "#{#avgTable?.get(2)?.get(0}"  // 缺少右括号
    

解决方案:

  • 检查表达式语法是否正确:
    "#{#avgTable?.get(2)?.get(0)}"  // 正确
    

推荐解决方案

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

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

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

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

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

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

总结

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

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

System.out.println("avgTable class: " + avgTable.getClass());
System.out.println("avgTable size: " + (avgTable != null ? avgTable.size() : "null"));

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

http://www.xdnf.cn/news/12123.html

相关文章:

  • 数据结构与算法学习笔记(Acwing 提高课)----动态规划·树形DP
  • 互联网大厂Java求职面试:云原生架构下的微服务网关与可观测性设计
  • SQL进阶之旅 Day 15:动态SQL与条件查询构建
  • 使用nginx代理mqtt服务
  • 算法分析与设计-动态规划、贪心算法
  • 对抗性提示:大型语言模型的安全性测试
  • 多模态大语言模型arxiv论文略读(107)
  • HTTP(超文本传输协议)详解
  • HarmonyOS Next 弹窗系列教程(4)
  • 【OpenGL学习】(四)统一着色和插值着色
  • 完成一个可交互的k8s管理平台的页面开发
  • [蓝桥杯]碱基
  • 2025年智能物联网与电子信息国际会议 (IITEI 2025)
  • QT开发技术【ffmpeg + QAudioOutput】音乐播放器
  • 【Docker 从入门到实战全攻略(二):核心概念 + 命令详解 + 部署案例】
  • [Java 基础]面向对象-多态
  • 电脑频繁黑屏怎么办
  • c++ STL 仿函数和适配器(算法常用)
  • 【Python金融笔记】加载数据与可视化
  • Appium+python自动化(八)- 认识Appium- 下章
  • JVM 内存溢出 详解
  • 数据结构第八章(一) 插入排序
  • DeviceNET从站转EtherNET/IP主站在盐化工行业的创新应用
  • 中国城市建成区数据集(1992-2020)V1.0
  • DataStreamAPI实践原理——快速上手(实操详细版)
  • skynet monitor线程的作用
  • Spring Boot 从Socket 到Netty网络编程(上):SOCKET 基本开发(BIO)与改进(NIO)
  • 大数据学习(130)-zookeeper
  • MP4文件声音与视频分离
  • 《高等数学》(同济大学·第7版)第一章第六节极限存在准则 两个重要极限