Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > JSTL: getting a map's keys

Reply
Thread Tools

JSTL: getting a map's keys

 
 
Chris Riesbeck
Guest
Posts: n/a
 
      03-19-2012
Can anyone help me figure out why the following is happening, or further
experiments I can run? (I have workarounds but I'd like to know what I'm
misunderstanding.)

Given:
- SimTable, a subclass of HashTable that defines getKeys() to call
keyset()
- a session variable "data" which is a HashTable with "rates" set to
an instance of a SimTable

Why does ${rates.keys} generate nothing in these lines of JSP?

<c:set var="rates" value='${data["rates"]}'/>

<p>rates: ${rates}</p>

<p>jstl: ${rates.keys}</p>

<p>jsp: <%= ((edu.northwestern.ils.simulator.SimTable)
pageContext.findAttribute("rates")).getKeys() %></p>

Here's the generated HTML output:

<p>rates: {Bill=100.0, Fred=75.0, Jane=75.0, Mary=50.0, Sam=75.0,
Sarah=150.0}</p>

<p>jstl: </p>

<p>jsp: [Bill, Fred, Jane, Mary, Sam, Sarah]</p>

 
Reply With Quote
 
 
 
 
Lew
Guest
Posts: n/a
 
      03-19-2012
On Monday, March 19, 2012 11:15:52 AM UTC-7, Chris Riesbeck wrote:
> Can anyone help me figure out why the following is happening, or further
> experiments I can run? (I have workarounds but I'd like to know what I'm
> misunderstanding.)
>
> Given:
> - SimTable, a subclass of HashTable [sic] that defines getKeys() to call


If you mean 'java.util.Hashtable', that's a rather obsolete class. You should stick with 'java.util.HashMap'.

> keyset()


Joshua Bloch recommends to prefer composition over inheritance.

> - a session variable "data" which is a HashTable with "rates" set to
> an instance of a SimTable


If "rates" is set to an instance of a 'HashTable', or whatever, is 'data' then a 'Map<String,Map<?,?>>'?

> Why does ${rates.keys} generate nothing in these lines of JSP?


How about you follow the advice here:
http://sscce.org/
and then maybe we can help you. It would make it easier for you to answer the questions I'm asking.

I think perhaps you're overthinking the session vars. Why can't your 'rates' Map go in there directly?

> <c:set var="rates" value='${data["rates"]}'/>
>
>
> rates: ${rates}</p>
>
>
> jstl: ${rates.keys}</p>
>
>
> jsp: <%= ((edu.northwestern.ils.simulator.SimTable)
> pageContext.findAttribute("rates")).getKeys() %></p>
>
> Here's the generated HTML output:
>
>
> rates: {Bill=100.0, Fred=75.0, Jane=75.0, Mary=50.0, Sam=75.0,
> Sarah=150.0}</p>
>
>
> jstl: </p>
>
>
> jsp: [Bill, Fred, Jane, Mary, Sam, Sarah]</p>


Your example code is fragmented and incomplete. Give us something we can work with, please.

--
Lew
 
Reply With Quote
 
 
 
 
Tim Slattery
Guest
Posts: n/a
 
      03-19-2012
Chris Riesbeck <(E-Mail Removed)> wrote:


> <p>jstl: ${rates.keys}</p>


The EL here finds the object "rates" and looks for an attribute named
"keys". That means that if rates doesn't have a public method named
getKeys, the EL won't find anything.

--
Tim Slattery
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
Chris Riesbeck
Guest
Posts: n/a
 
      03-19-2012
On 3/19/2012 3:08 PM, Tim Slattery wrote:
> Chris Riesbeck<(E-Mail Removed)> wrote:
>
>
>> <p>jstl: ${rates.keys}</p>

>
> The EL here finds the object "rates" and looks for an attribute named
> "keys". That means that if rates doesn't have a public method named
> getKeys, the EL won't find anything.
>

Which it does. Here's a complete example, class and test JSP, and the
HTML output I get

****** CLASS

package example;

import java.util.HashMap;
import java.util.Set;

public class SimTable extends HashMap<String, Object> {

public Set<String> getKeys() {
return keySet();
}
}

****** JSP

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%
final example.SimTable data = new example.SimTable();
data.put("Bill", 100); data.put("Mary", 150); data.put("Fred", 200);
pageContext.setAttribute("data", data);
%>

<!doctype HTML>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>data: ${data}</p>
<p>data.keys: ${data.keys}</p>
<p>data.getKeys():
<%= ((example.SimTable) pageContext.findAttribute("data")).getKeys() %>
</p>
</body>
</html>


****** HTML output

<!doctype HTML>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>data: {Bill=100, Mary=150, Fred=200}</p>
<p>data.keys: </p>
<p>data.getKeys():
[Bill, Mary, Fred]
</p>

</body>
</html>
 
Reply With Quote
 
Chris Riesbeck
Guest
Posts: n/a
 
      03-19-2012
On 3/19/2012 4:06 PM, Chris Riesbeck wrote:
> On 3/19/2012 3:08 PM, Tim Slattery wrote:
>> Chris Riesbeck<(E-Mail Removed)> wrote:
>>
>>
>>> <p>jstl: ${rates.keys}</p>

>>
>> The EL here finds the object "rates" and looks for an attribute named
>> "keys". That means that if rates doesn't have a public method named
>> getKeys, the EL won't find anything.
>>

> Which it does. Here's a complete example, class and test JSP, and the
> HTML output I get
>
> ****** CLASS
>
> package example;
>
> import java.util.HashMap;
> import java.util.Set;
>
> public class SimTable extends HashMap<String, Object> {
>
> public Set<String> getKeys() {
> return keySet();
> }
> }
>
> ****** JSP
>
> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
>
> <%
> final example.SimTable data = new example.SimTable();
> data.put("Bill", 100); data.put("Mary", 150); data.put("Fred", 200);
> pageContext.setAttribute("data", data);
> %>
>
> <!doctype HTML>
> <html>
> <head>
> <title>Test</title>
> </head>
> <body>
> <p>data: ${data}</p>
> <p>data.keys: ${data.keys}</p>
> <p>data.getKeys():
> <%= ((example.SimTable) pageContext.findAttribute("data")).getKeys() %>
> </p>
> </body>
> </html>
>
>
> ****** HTML output
>
> <!doctype HTML>
> <html>
> <head>
> <title>Test</title>
> </head>
> <body>
> <p>data: {Bill=100, Mary=150, Fred=200}</p>
> <p>data.keys: </p>
> <p>data.getKeys():
> [Bill, Mary, Fred]
> </p>
>
> </body>
> </html>


And I added these lines to my JSP to see if "keys" was appearing as a
property via the Introspector and it was

****** additional JSP

<c:set var="props"
value='<%=
java.beans.Introspector.getBeanInfo(pageContext.fi ndAttribute("data").getClass()).getPropertyDescrip tors()
%>' />
<ul>
<c:forEach var="prop" items="${props}">
<li>${prop.name}</li>
</c:forEach>
</ul>

****** additional HTML output

<ul>

<li>class</li>

<li>empty</li>

<li>keys</li>

</ul>

 
Reply With Quote
 
markspace
Guest
Posts: n/a
 
      03-19-2012
On 3/19/2012 1:08 PM, Tim Slattery wrote:
> Chris Riesbeck<(E-Mail Removed)> wrote:
>
>
>> <p>jstl: ${rates.keys}</p>

>
> The EL here finds the object "rates" and looks for an attribute named
> "keys". That means that if rates doesn't have a public method named
> getKeys, the EL won't find anything.
>



Up before the part you snipped, the OP mentioned that he did sub-class
HashTable and add a "getKeys()" method.

Hmm, maybe there's a clue there. Are there coercion rules for JSTL?
It's been a long while since I looked at it. Is it possible that JSTL
is coercing SimTable (the one with getKeys()) to a HashTable, which does
not have "getKeys()" defined?

You might want to uncompile the .class file for this JSTL, it might show
you what is actually being produced. There may be a clue there.


 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      03-19-2012
On 3/19/12 11:15 AM, Chris Riesbeck wrote:
> Can anyone help me figure out why the following is happening, or further
> experiments I can run? (I have workarounds but I'd like to know what I'm
> misunderstanding.)
>
> Given:
> - SimTable, a subclass of HashTable that defines getKeys() to call keyset()
> - a session variable "data" which is a HashTable with "rates" set to an
> instance of a SimTable
>
> Why does ${rates.keys} generate nothing in these lines of JSP?
>
> <c:set var="rates" value='${data["rates"]}'/>
>
> <p>rates: ${rates}</p>
>
> <p>jstl: ${rates.keys}</p>
>
> <p>jsp: <%= ((edu.northwestern.ils.simulator.SimTable)
> pageContext.findAttribute("rates")).getKeys() %></p>
>
> Here's the generated HTML output:
>
> <p>rates: {Bill=100.0, Fred=75.0, Jane=75.0, Mary=50.0, Sam=75.0,
> Sarah=150.0}</p>
>
> <p>jstl: </p>
>
> <p>jsp: [Bill, Fred, Jane, Mary, Sam, Sarah]</p>
>

My guess is that ${rates.keys} is interpreted as equivalent to
${rates['keys']}, so it is looking for a key of "keys", not a java bean
property.

You *can* use c:forEach to iterate over the entry set (Map.Entry) in a
map.

Hopefully this helps,
Daniel.
 
Reply With Quote
 
Chris Riesbeck
Guest
Posts: n/a
 
      03-20-2012
On 3/19/2012 6:59 PM, Daniel Pitts wrote:
> On 3/19/12 11:15 AM, Chris Riesbeck wrote:
>> Can anyone help me figure out why the following is happening, or further
>> experiments I can run? (I have workarounds but I'd like to know what I'm
>> misunderstanding.)
>>
>> Given:
>> - SimTable, a subclass of HashTable that defines getKeys() to call
>> keyset()
>> - a session variable "data" which is a HashTable with "rates" set to an
>> instance of a SimTable
>>
>> Why does ${rates.keys} generate nothing in these lines of JSP?
>>
>> <c:set var="rates" value='${data["rates"]}'/>
>>
>> <p>rates: ${rates}</p>
>>
>> <p>jstl: ${rates.keys}</p>
>>
>> <p>jsp: <%= ((edu.northwestern.ils.simulator.SimTable)
>> pageContext.findAttribute("rates")).getKeys() %></p>
>>
>> Here's the generated HTML output:
>>
>> <p>rates: {Bill=100.0, Fred=75.0, Jane=75.0, Mary=50.0, Sam=75.0,
>> Sarah=150.0}</p>
>>
>> <p>jstl: </p>
>>
>> <p>jsp: [Bill, Fred, Jane, Mary, Sam, Sarah]</p>
>>

> My guess is that ${rates.keys} is interpreted as equivalent to
> ${rates['keys']}, so it is looking for a key of "keys", not a java bean
> property.


Ah! This would explain why ${rates.class} doesn't work either.
Basically, name.key will always be taken as name[key] for a Map, even if
key is a property of name. If I'm reading the JSP EL resolver
specification correctly, that's just what is happening.

>
> You *can* use c:forEach to iterate over the entry set (Map.Entry) in a map.


Yes, that's what I've been doing instead for looping.

>
> Hopefully this helps,
> Daniel.


Indeed. Thanks, Daniel
 
Reply With Quote
 
Chris Riesbeck
Guest
Posts: n/a
 
      03-20-2012
On 3/20/2012 12:19 PM, Chris Riesbeck wrote:
> On 3/19/2012 6:59 PM, Daniel Pitts wrote:
>> On 3/19/12 11:15 AM, Chris Riesbeck wrote:
>>>
>>> [summary: rates is an instance of a subclass of Map that
>>> implements getKeys()]
>>>
>>> Why does ${rates.keys} generate nothing in these lines of JSP?
>>>

>> My guess is that ${rates.keys} is interpreted as equivalent to
>> ${rates['keys']}, so it is looking for a key of "keys", not a java bean
>> property.


Just to nail the coffin lid shut on this. The JSP EL defines name.key as
just shorthand for name["key"]. To interpret [] expressions, JSP uses
the first answer it gets from this chain of resolvers:

ImplicitObjectELResolver
registered custom ELResolvers
MapELResolver
ListELResolver
ArrayELResolver
BeanELResolver
ScopedAttributeELResolver


http://docs.oracle.com/javaee/5/api/...onContext.html

So the Map interpretation will always override the Bean interpretation.
 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      03-20-2012
Chris Riesbeck wrote:
> Chris Riesbeck wrote:
>> Daniel Pitts wrote:
>>> Chris Riesbeck wrote:
>>>>
>>>> [summary: rates is an instance of a subclass of Map that
>>>> implements getKeys()]
>>>>
>>>> Why does ${rates.keys} generate nothing in these lines of JSP?
>>>>
>>> My guess is that ${rates.keys} is interpreted as equivalent to
>>> ${rates['keys']}, so it is looking for a key of "keys", not a java bean
>>> property.

>
> Just to nail the coffin lid shut on this. The JSP EL defines name.key as
> just shorthand for name["key"]. To interpret [] expressions, JSP uses
> the first answer it gets from this chain of resolvers:
>
> ImplicitObjectELResolver
> registered custom ELResolvers
> MapELResolver
> ListELResolver
> ArrayELResolver
> BeanELResolver
> ScopedAttributeELResolver
>
>
> http://docs.oracle.com/javaee/5/api/...onContext.html
>
> So the Map interpretation will always override the Bean interpretation.


Now that your main question is answered, a couple of comments are in order.

- Don't have scriptlet in your JSPs.
- If you had *composed* a 'Map' into a custom class rather than inheriting 'Map', you would not have had the problem. Your custom class would have been resolved by the bean resolver.
- This in turn would make for a better design overall. Instead of your viewartifact (the JSP) caring about the implementation details of the map and its set of keys, you'd have a controller call like 'getKeys()' or whatever that would cleanly separate the logic of how you get them from presentationconcerns.

--
Lew
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing map keys (no reordering of keys) alan C++ 3 11-28-2007 03:17 PM
How to link foreign keys & primary keys using python? Harry George Python 9 06-13-2006 06:29 AM
can std::set hold pointers to keys instead of the keys themselves? danibe@my-deja.com C++ 10 02-03-2006 03:44 AM
serial keys/validation keys sandeep Kanwal C++ 1 10-29-2004 06:36 PM
keyboard keys replacing mouse keys? larry Computer Support 8 09-14-2003 07:32 PM



Advertisments