Manipulating Lists in JSTL
May 21st, 2008A common problem when coding in JSTL is that you would like to have an ArrayList of items that you can iterate over. For example imagine that you have a list of Animals like:
1) Sylvester
2) Goofy
3) Mickey
<c:forEach items="${animalList}" var="animal">${animal}<</c:forEach>
And you would like the output to be in the same order:
Sylvester
Goofy
Mickey
The problem is that you can’t do this:
<jsp:useBean id=”animalList” class=”java.util.ArrayList”/>
because <c:set> doesn’t work with <i>ArrayLists</i>, and so there is no good way to use JSTL to add those values.
This fails:
<c:set target=”${animalList}” value=”Sylvester”/>
<c:set target=”${animalList}” value=”Goofy”/>
<c:set target=”${animalList}” value=”Mickey”/>
You could do this, and I wouldn’t argue if you do:
<c:set var=”dummyVar” value=”${animalList.add(’Sylvester’)}”/>
<c:set var=”dummyVar” value=”${animalList.add(’Goofy’)}”/>
<c:set var=”dummyVar” value=”${animalList.add(’Mickey’)}”/>
However, its a little ugly, because you have to use dummyVars. Still I will admit I have used this technique a lot. Another solution that you might be considering is to use HashMaps, which do work with <c:set>.
<jsp:useBean id=”animalMap” class=”java.util.HashMap”/>
<c:set target=”${animalMap}” property=”cat” value=”Sylvester”/>
<c:set target=”${animalMap}” property=”dog” value=”Goofy”/>
<c:set target=”${animalMap}” property=”rat” value=”Rat”/>
<c:forEach items=”${animalMap.values()}” var=”animal”>
${animal}<br>
</c:forEach>
This is cool because there is not hackish method calls on objects that JSTL doesn’t understand. Also the elements can now be referenced indirectly, instead of having to loop on the list to find a particular element. But there is a problem: The order has been lost! When this loop fires it dumps the animals in the order that they are stored in the HashMap, which for all practical purposes is random.
The solution: <b>java.util.LinkedHashMap</b>
By replacing java.util.HashMap in the example above with
java.util.LinkedHashMap, you get the best of both worlds! <b>Ordered
elements</b> and <b>Indirect Reference</b>:
<jsp:useBean id=”animalMap” class=”java.util.LinkedHashMap”/>
<c:set target=”${animalMap}” property=”cat” value=”Sylvester”/>
<c:set target=”${animalMap}” property=”dog” value=”Goofy”/>
<c:set target=”${animalMap}” property=”rat” value=”Rat”/>
These are ordered:<br>
<c:forEach items=”${animalMap.values()}” var=”animal”>
${animal}<br>
</c:forEach>
And this references a particular element:<br>
${animalMap[’dog’]}