J'ai une carte saisie par Integer. En utilisant EL, comment puis-je accéder à une valeur par sa clé?
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
Je pensais que cela fonctionnerait mais ça ne marche pas (où map est déjà dans les attributs de la requête):
<c:out value="${map[1]}"/>
Suivi: J'ai retrouvé le problème. Apparemment ${name[1]}
effectue une recherche sur la carte avec le numéro sous la forme Long
. J'ai compris cela quand j'ai changé HashMap
en TreeMap
et que j'ai reçu l'erreur:
Java.lang.ClassCastException: Java.lang.Integer cannot be cast to Java.lang.Long
Si je change ma carte pour être:
Map<Long, String> map = new HashMap<Long, String>();
map.put(1L, "One");
puis ${name[1]}
renvoie "Un". C'est quoi ça? Pourquoi <c:out>
traiter un nombre comme un long. Cela me semble contre-intuitif (car int est plus utilisé que long).
Ma nouvelle question est donc la suivante: existe-t-il une notation EL permettant d’accéder à une carte par une valeur Integer
?
Réponse initiale (EL 2.1, mai 2009)
Comme mentionné dans this Java sujet du forum :
Fondamentalement, l'autoboxing place un objet Integer dans la carte. c'est à dire:
map.put(new Integer(0), "myValue")
EL (Expressions Languages) évalue 0 comme un long et va donc chercher un long comme clé dans la carte. c'est à dire qu'il évalue:
map.get(new Long(0))
Comme Long
n'est jamais égal à un objet Integer
, il ne trouve pas l'entrée dans la carte.
Voilà en quelques mots.
Dec 2009 a vu l'introduction de EL 2.2 avec JSP 2.2/Java EE 6 , avec un peu de différences par rapport à EL 2.1 .
Il semble (" Expression syntaxique d'un nombre entier tant que long "):
vous pouvez appeler la méthode
intValue
sur l'objetLong
à l'intérieur de l'EL 2.2 :
<c:out value="${map[(1).intValue()]}"/>
Cela pourrait être une bonne solution de contournement ici (également mentionné ci-dessous dans Tobias Liefkeréponse )
Réponse originale:
EL utilise les wrappers suivants:
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
Page JSP démontrant ceci:
<%@ 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>
Un autre conseil utile, en plus du commentaire ci-dessus, serait lorsque vous avez une valeur de chaîne contenue dans une variable telle qu'un paramètre de requête. Dans ce cas, si vous transmettez cette action, JSTL saisira également la valeur de "1" en tant que commande et en tant que telle, aucune correspondance ne sera trouvée dans une carte de hachage de carte.
Une façon de contourner cela est de faire quelque chose comme ça.
<c:set var="longKey" value="${param.selectedIndex + 0}"/>
Celui-ci sera désormais traité comme un objet long et aura ensuite la possibilité de faire correspondre un objet s'il est contenu dans la carte, ou autre.
Ensuite, continuez comme d'habitude avec quelque chose comme
${map[longKey]}
Vous pouvez utiliser toutes les fonctions de Long si vous mettez le numéro entre "(" ")". De cette façon, vous pouvez lancer le long vers un int:
<c:out value="${map[(1).intValue()]}"/>
Sur la base du message ci-dessus, j'ai essayé ceci et cela a bien fonctionné. Je voulais utiliser la valeur de la carte B comme clé de la carte 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>
S'il vous arrive d'avoir un Map
avec des clés Integer
que vous ne pouvez pas modifier, vous pouvez écrire un fonction EL personnalisée pour convertir un Long
en Integer
. Cela vous permettrait de faire quelque chose comme:
<c:out value="${map[myLib:longToInteger(1)]}"/>