web-dev-qa-db-fra.com

EL accéder à une valeur de carte par la clé Integer

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?

85
Steve Kuo

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.


Mise à jour depuis mai 2009 (EL 2.2)

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'objet Long à 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>
114
VonC

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]}
11
Dave

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()]}"/>
8
Tobias Liefke

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>
3
Dhanashri

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)]}"/>
2
Jasper de Vries