首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Tomcat 6/7 EL 表達式類型轉換 Bug 分析與解決方案

     編輯:Java 相關知識

Bug 現象

在 JSP 中使用 JSTL <c:forEach> 遍歷 List<String>,並在 <c:when test="${looper eq pageHelper.pageNo}"> 比較時,若 pageNo 為 Long 型別,Tomcat 6.0.36 / 7.0.30 會拋出:

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

原因分析

  1. EL 表達式解析器在首次比較時,發現 pageNo 為 Long,決定將後續比較的 looper 也轉為 Long。
  2. 當 looper 為 "..."(分頁省略號)時,無法轉型為 Long,導致異常。
  3. Resin 等其他容器會將兩邊統一轉為 String 比較,不會出錯。

重現代碼片段

<c:forEach var="looper" items="${pageHelper.pageList}">
    <c:choose>
        <c:when test="${looper eq pageHelper.pageDot}">...</c:when>
        <c:when test="${looper eq pageHelper.pageNo}">當前頁</c:when>
        <c:otherwise>${looper}</c:otherwise>
    </c:choose>
</c:forEach>

解決方案:強制轉為 String 比較

使用 JSTL fn:trim 或 fn:toString 將比較右邊轉為字串:

<%@ taglib prefix="fn" uri="https://java.sun.com/jsp/jstl/functions" %>
...
<c:when test="${looper eq fn:trim(pageHelper.pageNo)}">當前頁</c:when>
<c:when test="${looper eq fn:trim(pageHelper.pageDot)}">...</c:when>

其他替代方案

  • 後端統一型別:Controller 中將 pageNo 轉為 String 再放入 Model。
  • 自定義 EL 函數:編寫 eqStr 函數統一走字串比較邏輯。
  • 升級容器:Tomcat 8.5+ 已修正此行為,建議升級。

驗證測試

// 測試用例
List<String> list = Arrays.asList("1", "...", "3", "4");
Long pageNo = 3L;
String pageDot = "...";

for (String s : list) {
    // 錯誤寫法:s == pageNo 會觸發 EL 轉型邏輯
    // 正確寫法:
    if (s.equals(pageDot)) { ... }
    else if (s.equals(String.valueOf(pageNo))) { ... }
}

總結

此為 Tomcat EL 實作缺陷,核心在於類型推斷順序導致非預期轉型。開發時應遵循「比較雙方型別一致」原則,或在 EL 中顯式轉型,避免依賴容器隱式轉換行為。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved