Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EL access a map value by Integer key

Tags:

java

jsp

jstl

el

I have a Map keyed by Integer. Using EL, how can I access a value by its key?

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

I thought this would work but it doesn't (where map is already in the request's attributes):

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

Follow up: I tracked down the problem. Apparently ${name[1]} does a map lookup with the number as a Long. I figured this out when I changed HashMap to TreeMap and received the error:

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

If I change my map to be:

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

then ${name[1]} returns "One". What's with that? Why does <c:out> treat a number as a long. Seems counterintuitive to me (as int is more commonly used than long).

So my new question is, is there a EL notation to access a map by an Integer value?

like image 754
Steve Kuo Avatar asked May 29 '09 04:05

Steve Kuo


People also ask

Can HashMap have integer keys?

It can store different types: Integer keys and String values or same types: Integer keys and Integer values. HashMap is similar to HashTable, but it is unsynchronized. It is allowed to store null keys as well, but there can only be one null key and there can be any number of null values.

How do you set a value on a map?

put() method of HashMap is used to insert a mapping into a map. This means we can insert a specific key and the value it is mapping to into a particular map. If an existing key is passed then the previous value gets replaced by the new value. If a new pair is passed, then the pair gets inserted as a whole.


1 Answers

Initial answer (EL 2.1, May 2009)

As mentioned in this java forum thread:

Basically autoboxing puts an Integer object into the Map. ie:

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

EL (Expressions Languages) evaluates 0 as a Long and thus goes looking for a Long as the key in the map. ie it evaluates:

map.get(new Long(0)) 

As a Long is never equal to an Integer object, it does not find the entry in the map.
That's it in a nutshell.


Update since May 2009 (EL 2.2)

Dec 2009 saw the introduction of EL 2.2 with JSP 2.2 / Java EE 6, with a few differences compared to EL 2.1.
It seems ("EL Expression parsing integer as long") that:

you can call the method intValue on the Long object self inside EL 2.2:

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

That could be a good workaround here (also mentioned below in Tobias Liefke's answer)


Original answer:

EL uses the following wrappers:

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 page demonstrating this:

 <%@ 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> 
like image 110
VonC Avatar answered Oct 02 '22 08:10

VonC