解析Tomcat 6、7在EL表达式解析时存在的一个Bug

时间:2023-07-03 22:02:50 

今天在做数据分页显示的时候遇到了一个问题,经过测试,证实是Tomcat 6的一个bug,我所用的版本为:apache-tomcat-6.0.36,和7.0.30均能复现。下面详细描述一下这个bug:

该bug是在JSTL<c:forEach>标签中发现的,后来分析是EL表达式实现时产生的问题。jsp页面中有一个list需要遍历,这个list的类型为ArrayList<String>,我在其中放置的数据为(为方便我写成数组的形式):["1","...","4","5","6","7","8","...","10"],这是一个很常见的带页码缩略的分页导航。在展示这些数据的时候我使用了下面的代码:


<c:forEach var="looper" items="${pageHelper.pageList}">
 <c:choose>
  <c:when test="${looper eq pageHelper.pageDot}">
  <p>分页游标的 点点点</p>
  </c:when>
  <c:when test="${looper eq pageHelper.pageNo}">
  <p>当前页为第${looper}页面</p>
  </c:when>
  <c:otherwise>
  <p>分页游标:${looper}</p>
  </c:otherwise>
 </c:choose>
</c:forEach>


这里pageHelper就是分页组件,其中预设了pageDot为"...",pageNo为当前的页码(假设为6),其他情况直接显示分页游标。在循环遍历中只不过使用了最基本的条件判断语句,由于pageList在定义中已经明确指出是List<String>,按逻辑应该eq是按照字符串判断的,但是居然出异常了:


javax.el.ELException: Cannot convert ... of type class java.lang.String to class java.lang.Long


为什么会出现“类型转换错误”呢?通过分析代码走向,当进入循环后,list中的第一条数据是“1”,而pageHelper.pageNo为long型,此时tomcat的EL表达式解析器会把looper类型转换为Long型而不是把pageHelper.pageNo类型转换为String进行比较,当遍历到下一元素时,looper="...",这时looper的类型已经确定,比较的时候tomcat还要试图将looper转换为Long类型,于是就出错了。

为此我专门写了一个实例代码:


<c:forEach var="looper" items="${pageHelper.pageList}">
 <c:choose>
  <c:when test="${looper eq fn:trim(pageHelper.pageDot)}">
  <p>分页游标的 点点点</p>
  </c:when>
  <c:when test="${looper eq fn:trim(pageHelper.pageNo)}">
  <p>当前页为第${looper}页面</p>
  </c:when>
  <c:otherwise>
  <p>分页游标:${looper}</p>
  </c:otherwise>
 </c:choose>
</c:forEach>


很简单,每次比较的时候都把后者用fn:trim方法进行去除左右非可见字符。相当于强制转换为String类型,此时tomcat又可以正常解析代码,并未报错。

同样的一套代码,我将其部署到resin中发现无论是修改前还是修改后都能正常运行,可见,应该是tomcat的bug。

示例代码:点击下载

让tomcat报错的演示地址:/bug/show.do

避免此bug的方法演示地址:/bug/avoid.do

以上地址前可能需要加上项目名称(具体取决于你如何部署该项目)

标签:EL,表达式,Tomcat
0
投稿

猜你喜欢

  • Mybatis-Plus查询中如何排除标识字段

    2023-11-23 20:38:46
  • Android语音声波控件 Android条形波控件

    2023-10-29 02:03:05
  • SpringBoot项目jar和war打包部署方式详解

    2023-05-10 14:58:29
  • java 打造阻塞式线程池的实例详解

    2022-09-13 09:50:33
  • java实现猜字母游戏

    2021-11-19 22:25:28
  • SpringSecurity rememberme功能实现过程解析

    2021-12-20 05:22:08
  • Android应用App更新实例详解

    2023-06-26 21:27:44
  • c#基于WinForm的Socket实现简单的聊天室 IM

    2021-11-27 04:47:57
  • Android截屏SurfaceView黑屏问题的解决办法

    2023-10-23 11:12:25
  • Android用户输入自动提示控件AutoCompleteTextView使用方法

    2022-02-25 14:59:50
  • 用C#将图片保存至Oracle BLOB字段中的方法

    2023-06-12 01:29:16
  • Android6.0仿微信权限设置

    2023-03-03 09:40:30
  • mybatis框架xml下trim中的prefix与suffix等标签的用法

    2023-09-20 18:55:24
  • C#中事件的动态调用实现方法

    2022-08-29 03:27:28
  • 详解JAVA 抽象类

    2022-12-15 19:29:20
  • Java中MyBatis Plus知识点总结

    2023-08-11 14:12:04
  • Spring ApplicationListener监听器用法详解

    2022-08-21 00:00:08
  • 21天学习android开发教程之SurfaceView

    2023-04-17 17:01:56
  • Kotlin Thread线程与UI更新详解

    2021-10-10 00:18:22
  • linux的shell命令检测某个java程序是否执行

    2021-07-27 14:32:20
  • asp之家 软件编程 m.aspxhome.com