EL accede a un valore della mappa tramite la chiave Integer


85

Ho una mappa codificata da Integer. Utilizzando EL, come posso accedere a un valore tramite la sua chiave?

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

Ho pensato che avrebbe funzionato ma non funziona (dove la mappa è già negli attributi della richiesta):

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

Follow up: ho rintracciato il problema. Apparentemente ${name[1]}fa una ricerca sulla mappa con il numero come file Long. L'ho capito quando sono passato HashMapa TreeMape ho ricevuto l'errore:

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

Se cambio la mia mappa in:

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

quindi ${name[1]}restituisce "Uno". Che succede? Perché <c:out>tratta un numero come un lungo. Mi sembra controintuitivo (dato che int è più comunemente usato che long).

Quindi la mia nuova domanda è: esiste una notazione EL per accedere a una mappa in base a un Integervalore?

Risposte:


117

Risposta iniziale (LE 2.1, maggio 2009)

Come menzionato in questo thread del forum java :

Fondamentalmente l'autoboxing inserisce un oggetto Integer nella mappa. cioè:

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

EL (Expressions Languages) valuta 0 come Long e quindi cerca un Long come chiave nella mappa. ovvero valuta:

map.get(new Long(0))

Poiché a Longnon è mai uguale a un Integeroggetto, non trova la voce nella mappa.
Questo è tutto in poche parole.


Aggiornamento da maggio 2009 (EL 2.2)

Il dicembre 2009 ha visto l'introduzione di EL 2.2 con JSP 2.2 / Java EE 6 , con alcune differenze rispetto a EL 2.1 .
Sembra (" EL Expression parsing integer as long ") che:

è possibile chiamare il metodo intValuein Longsé oggetto all'interno EL 2.2 :

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

Questo potrebbe essere un buona soluzione alternativa qui (menzionata anche al di sotto di Tobias Liefke 's risposta )


Risposta originale:

EL utilizza i seguenti wrapper:

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

Pagina JSP che lo dimostra:

 <%@ 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>

Quindi non c'è modo di convincere EL per espandere un numero come Integer?
Steve Kuo,

1
@ Steve: in effetti, EL non sembra supportarlo.
VonC

Ho trovato questa domanda e risposta da una ricerca su Google. Abbastanza sicuro, non appena sono passato da Map <Integer, String> a Map <Long, String> sono stato in grado di estrarre da esso utilizzando l'EL che avevo nella mia pagina JSP. Grazie!!
John Munsch

@Steve: È possibile - vedi la mia risposta
Tobias Liefke

@SteveKuo Dovrebbe essere davvero possibile. Ora mi rendo conto che questa risposta vecchia di 6 anni è stata scritta quando EL 2.2 non era ancora stato rilasciato. Ho modificato e aggiornato detta risposta.
VonC

11

Solo un altro suggerimento utile in aggiunta al commento sopra sarebbe quando hai un valore di stringa contenuto in una variabile come un parametro di richiesta. In questo caso, trasmettendolo si tradurrà anche in JSTL che digita il valore di say "1" come pungiglione e come tale non viene trovata alcuna corrispondenza in una mappa hash Map.

Un modo per aggirare questo problema è fare qualcosa di simile.

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

Questo verrà ora trattato come un oggetto lungo e quindi avrà la possibilità di abbinare un oggetto quando è contenuto all'interno della mappa o altro.

Quindi, continua come al solito con qualcosa di simile

${map[longKey]}

10

È possibile utilizzare tutte le funzioni da Long, se si inserisce il numero in "(" ")". In questo modo puoi lanciare il long a un int:

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

Non ho visto subito la tua risposta. +1. Ho incluso e documentato questa possibilità nella mia risposta per una maggiore visibilità.
VonC

3

Sulla base del post sopra ho provato questo e ha funzionato bene, volevo usare il valore della mappa B come chiavi per la mappa 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

Se ti capita di avere un Mapcon Integerchiavi che non puoi modificare, potresti scrivere una funzione EL personalizzata per convertire un Longin Integer. Questo ti consentirebbe di fare qualcosa come:

<c:out value="${map[myLib:longToInteger(1)]}"/>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.