views:

2834

answers:

3

Hi all,

I'm having some trouble looping over a HashMap to print out it's values to the screen. Could someone double check my code to see what I'm doing wrong. I can't seem to find anything wrong but there must be something.

In a servlet, I am adding the following to the request:

Map<String, String> facetValues = new HashMap<String, String>();
// Filling the map
req.setAttribute(facetField.getName(), facetValues);

In one case "facetField.getName()" evaluates to "discipline". So in my page I have the following:

<ui:repeat value="${requestScope.discipline}" var="item">
  <li>Item: <c:out value="${item}"/>, Key: <c:out value="${item.key}"/>, Value: <c:out value="${item.item}"/></li>
</ui:repeat>

The loop is ran once but all the outputs are blank?!? I would have at least expected something in item if it's gone over the loop once. Checking the debug popup for Facelets, discipline is there and on the loop. Printing it to the screen results in something that looks like a map to me (I've shortened the output) :

{300=0, 1600=0, 200=0, ... , 2200=0}

I've also tried with a c:forEach but I'm getting the same results. So does anyone have any ideas where I'm going wrong?

Thanks for any input, Lee

A: 

Three things occur to me:

1.

The documentation for ui:repeat doesn't say it (it only says List), but I see UIRepeat uses DataModel as its model (in the manner of h:dataTable). Map will not be automatically wrapped with a DataModel type - the type is not implicitly supported. You will need to either make the value an instance of your own DataModel implementation or provide them as an implicitly supported type (e.g. java.util.List).

2.

I am not sure what you intend these values to map to:

${item}
${item.key}
${item.item}

If you change "discipline" to be of type List<Map.Entry<String,String>>, you could bind to the key and value properties:

${item.key}
${item.value}

You can create your list like so:

Map<String, String> facetValues = new HashMap<String, String>();
// Filling the map
List<Map.Entry<String, String>> discipline
        = new ArrayList<Map.Entry<String, String>>(facetValues.entrySet());

3.

The FAQ suggests that JSTL tags are only evaluated at component tree creation time. It is unclear to me whether using c:out as a child of ui:repeat will work properly. You might need to use h:outputText instead. (I could be wrong about this, of course - I have not tried it.)


In a servlet, I am adding the following to the request

That sounds like an odd way to put something into request scope in JSF, but I'll trust that you know what you're doing!

McDowell
+1  A: 

In a c:forEach with a Map value, every iteration gives a Map.Entry which has only getKey() and getValue() methods (and thus not getItem() as you seemed to think). Thus, the following should work fine:

<ul>
    <c:forEach items="${map}" var="entry">
        <li>Key: ${entry.key}, value: ${entry.value}</li>
    </c:forEach>
</ul>

If you just print the ${map} you would only see the outcome of Map#toString(), which has thus the following format {300=0, 1600=0, 200=0, ... , 2200=0}. You also see, I didn't use <c:out>, that is not necessary as the map seemed to contain server-side controlled numerical values (which doesn't need to be HTML-escaped) and Facelets just supports EL in template text (as does JSP 2.0 and newer).

The JSF UIData components unfortunately doesn't support Maps. Only the JSF UISelectItems (e.g. f:selectItems) does support it, but that's not what you need. If you want to use an UIData component (in which I would recommend Tomahawk's t:dataList layout="unorderedList" for this particular purpose), then better use a List<Pair> wherein Pair is just a javabean with two properties.

That said, using a servlet to prepopulate this is a bit odd/cumbersome as JSF already provides you a component based MCV framework which should remove the need to create separate servlets. Just have a managed bean with a Map property and access it as #{bean.map} in the c:forEach.

BalusC
+1  A: 

<ui:repeat> only accepts List or DataModel, not Sets or Maps. This is on the roadmap for JSF 2.1.

Lincoln