EL truy cập một giá trị bản đồ bằng khóa Số nguyên


85

Tôi có một Bản đồ được khóa bằng Số nguyên. Sử dụng EL, làm cách nào tôi có thể truy cập một giá trị bằng khóa của nó?

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

Tôi nghĩ điều này sẽ hoạt động nhưng nó không hoạt động (nơi bản đồ đã có trong các thuộc tính của yêu cầu):

<c:out value="${map[1]}"/>

Theo dõi: Tôi đã theo dõi vấn đề. Rõ ràng ${name[1]}có một tra cứu bản đồ với số là a Long. Tôi đã tìm ra điều này khi tôi đổi HashMapthành TreeMapvà nhận được lỗi:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

Nếu tôi thay đổi bản đồ của mình thành:

Map<Long, String> map = new HashMap<Long, String>();
map.put(1L, "One");

sau đó ${name[1]}trả về "Một". Cái gì vậy? Tại sao lại <c:out>coi một số là dài. Có vẻ trái ngược với tôi (vì int được sử dụng phổ biến hơn dài).

Vì vậy, câu hỏi mới của tôi là, có ký hiệu EL để truy cập bản đồ theo một Integergiá trị không?

Câu trả lời:


117

Câu trả lời ban đầu (EL 2.1, tháng 5 năm 2009)

Như đã đề cập trong chủ đề diễn đàn java này :

Về cơ bản autoboxing đặt một đối tượng Integer vào Bản đồ. I E:

map.put(new Integer(0), "myValue")

EL (Expressions Languages) đánh giá 0 là Long và do đó tìm kiếm Long làm chìa khóa trong bản đồ. tức là nó đánh giá:

map.get(new Long(0))

Vì a Longkhông bao giờ bằng một Integerđối tượng, nó không tìm thấy mục nhập trong bản đồ.
Tóm lại là vậy.


Cập nhật kể từ tháng 5 năm 2009 (EL 2.2)

Tháng 12 năm 2009 chứng kiến ​​sự ra đời của EL 2.2 với JSP 2.2 / Java EE 6 , với một vài khác biệt so với EL 2.1 .
Có vẻ như (" EL Expression parsing integer as long ") rằng:

bạn có thể gọi phương thức intValuetrên Longđối tượng self bên trong EL 2.2 :

<c:out value="${map[(1).intValue()]}"/>

Đó có thể là một giải pháp tốt ở đây (cũng được đề cập bên dưới trong câu trả lời của Tobias Liefke )


Câu trả lời ban đầu:

EL sử dụng các trình bao bọc sau:

Terms                  Description               Type
null                   null value.               -
123                    int value.                java.lang.Long
123.00                 real value.               java.lang.Double
"string" ou 'string'   string.                   java.lang.String
true or false          boolean.                  java.lang.Boolean

Trang JSP chứng minh điều này:

 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

 <%@ page import="java.util.*" %>

 <h2> Server Info</h2>
Server info = <%= application.getServerInfo() %> <br>
Servlet engine version = <%=  application.getMajorVersion() %>.<%= application.getMinorVersion() %><br>
Java version = <%= System.getProperty("java.vm.version") %><br>
<%
  Map map = new LinkedHashMap();
  map.put("2", "String(2)");
  map.put(new Integer(2), "Integer(2)");
  map.put(new Long(2), "Long(2)");
  map.put(42, "AutoBoxedNumber");

  pageContext.setAttribute("myMap", map);  
  Integer lifeInteger = new Integer(42);
  Long lifeLong = new Long(42);  
%>
  <h3>Looking up map in JSTL - integer vs long </h3>

  This page demonstrates how JSTL maps interact with different types used for keys in a map.
  Specifically the issue relates to autoboxing by java using map.put(1, "MyValue") and attempting to display it as ${myMap[1]}
  The map "myMap" consists of four entries with different keys: A String, an Integer, a Long and an entry put there by AutoBoxing Java 5 feature.       

  <table border="1">
    <tr><th>Key</th><th>value</th><th>Key Class</th></tr>
    <c:forEach var="entry" items="${myMap}" varStatus="status">
    <tr>      
      <td>${entry.key}</td>
      <td>${entry.value}</td>
      <td>${entry.key.class}</td>
    </tr>
    </c:forEach>
</table>

    <h4> Accessing the map</h4>    
    Evaluating: ${"${myMap['2']}"} = <c:out value="${myMap['2']}"/><br>
    Evaluating: ${"${myMap[2]}"}   = <c:out value="${myMap[2]}"/><br>    
    Evaluating: ${"${myMap[42]}"}   = <c:out value="${myMap[42]}"/><br>    

    <p>
    As you can see, the EL Expression for the literal number retrieves the value against the java.lang.Long entry in the map.
    Attempting to access the entry created by autoboxing fails because a Long is never equal to an Integer
    <p>

    lifeInteger = <%= lifeInteger %><br/>
    lifeLong = <%= lifeLong %><br/>
    lifeInteger.equals(lifeLong) : <%= lifeInteger.equals(lifeLong) %> <br>

Vậy không có cách nào để EL mở rộng một số dưới dạng Số nguyên?
Steve Kuo

1
@Steve: thực sự thì EL dường như không ủng hộ điều đó.
VonC

Tôi đã tìm thấy câu hỏi và câu trả lời này từ một tìm kiếm trên Google. Chắc chắn rồi, ngay sau khi tôi chuyển từ Bản đồ <Số nguyên, Chuỗi> sang Bản đồ <Dài, Chuỗi>, tôi đã có thể lấy từ nó bằng EL mà tôi có trong trang JSP của mình. Cảm ơn!!
John Munsch

@Steve: Có thể - hãy xem câu trả lời của tôi
Tobias Liefke

@SteveKuo Thực sự là có thể. Bây giờ tôi nhận ra rằng câu trả lời 6 năm tuổi này đã được viết khi EL 2.2 chưa được phát hành. Tôi đã chỉnh sửa và cập nhật câu trả lời cho biết.
VonC

11

Chỉ một gợi ý hữu ích khác ngoài nhận xét trên sẽ là khi bạn có một giá trị chuỗi chứa trong một số biến như tham số yêu cầu. Trong trường hợp này, việc chuyển giá trị này vào cũng sẽ dẫn đến việc JSTL khóa giá trị của nói "1" như một dấu chấm và do đó không tìm thấy kết quả khớp nào trong Bản đồ băm.

Một cách để giải quyết vấn đề này là làm điều gì đó như thế này.

<c:set var="longKey" value="${param.selectedIndex + 0}"/>

Nó bây giờ sẽ được coi là một Long đối tượng và sau đó có cơ hội khớp với một đối tượng khi nó được chứa trong bản đồ Bản đồ hoặc bất cứ thứ gì.

Sau đó, tiếp tục như bình thường với những thứ như

${map[longKey]}

10

Bạn có thể sử dụng tất cả các hàm từ Long, nếu bạn đặt số vào "(" ")". Bằng cách đó, bạn có thể truyền long thành int:

<c:out value="${map[(1).intValue()]}"/>

Tôi không thấy câu trả lời của bạn ngay lập tức. +1. Tôi đã bao gồm và ghi lại khả năng đó trong câu trả lời của mình để dễ thấy hơn.
VonC

3

Dựa trên bài đăng trên, tôi đã thử điều này và điều này hoạt động tốt. Tôi muốn sử dụng giá trị của Bản đồ B làm khóa cho Bản đồ A:

<c:if test="${not empty activityCodeMap and not empty activityDescMap}">
<c:forEach var="valueMap" items="${auditMap}">
<tr>
<td class="activity_white"><c:out value="${activityCodeMap[valueMap.value.activityCode]}"/></td>
<td class="activity_white"><c:out value="${activityDescMap[valueMap.value.activityDescCode]}"/></td>
<td class="activity_white">${valueMap.value.dateTime}</td>
</tr>
</c:forEach>
</c:if>

3

Nếu bạn chỉ tình cờ có một Mapvới Integercác phím mà bạn không thể thay đổi, bạn có thể viết một hàm EL tùy chỉnh để chuyển đổi một Longthành Integer. Điều này sẽ cho phép bạn làm điều gì đó như:

<c:out value="${map[myLib:longToInteger(1)]}"/>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.