Pergunta

Eu tenho um mapa chaveado por inteiro. Usando EL, como posso acessar um valor por sua chave?

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

Eu pensei que isso iria funcionar, mas não (onde mapa já está em atributos do pedido):

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

Acompanhamento: Eu rastreou o problema. Aparentemente ${name[1]} faz uma pesquisa mapa com o número como um Long. Eu descobri isso quando eu mudei HashMap para TreeMap e recebeu o erro:

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

Se eu mudar meu mapa a ser:

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

retorna então ${name[1]} "One". O que é com isso? Por que <c:out> tratar um número como uma longa. Parece contra-intuitivo para mim (como int é mais comumente usado de comprimento).

Assim, a minha nova pergunta é, existe uma notação EL para acessar um mapa por um valor Integer?

Foi útil?

Solução

resposta inicial (EL 2.1, maio de 2009)

Conforme mencionado na esta java tópico do fórum :

Basicamente autoboxing coloca um objeto Integer para o Mapa. ou seja:

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

EL (Expressões Línguas) avalia 0 como um longo e, portanto, vai à procura de uma longa como a chave no mapa. ou seja, ele avalia:

map.get(new Long(0))

Como Long nunca é igual a um objeto Integer, não encontrar a entrada no mapa.
É isso em poucas palavras.


Atualização desde maio de 2009 (EL 2.2)

dezembro 2009 viu a introdução de EL 2.2 com JSP 2.2 / Java EE 6 , com um few diferenças em relação ao EL 2.1 .
Parece ( " EL Expression análise inteiro desde ") que:

você pode chamar o intValue método no Long objeto auto dentro EL 2.2 :

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

Isso poderia ser uma boa solução aqui (também mencionado no Tobias Liefke 's answer )


resposta Original:

EL utiliza as seguintes embalagens:

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

JSP página demonstrando isto:

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

Outras dicas

Apenas uma outra dica útil além do comentário acima seria quando você tem um valor de string contido em alguma variável como um parâmetro de solicitação. Neste caso, passar isso em também irá resultar em JSTL digitando o valor de dizer "1" como uma picada e como tal não é páreo, sendo encontrado em um hashmap Mapa. ??

Uma maneira de contornar este problema é fazer algo parecido com isso.

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

Este será agora tratado como um objeto longo e, em seguida, tem a chance de igualar um objeto quando ele está contido withing o mapa Mapa ou o que quer.

Em seguida, continue como de costume com algo como

${map[longKey]}

Você pode usar todas as funções de Long, se você colocar o número em "(" ")". Dessa forma, você pode lançar o longo para um int:

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

Com base no post acima, eu tentei isso e isso muito bem trabalhado Eu queria usar o valor do Mapa B como chaves para Map 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>

Se você acabou de acontecer de ter uma Map com chaves Integer você não pode mudar, você poderia escrever um costume função EL para converter um Long para Integer. Isso permitiria que você a fazer algo como:

<c:out value="${map[myLib:longToInteger(1)]}"/>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top