How to Iterate Over java.util.Set in JSF

I spent quite some time trying to find a solution for the following JSF issue: it is not possible to iterate over a java.util.Set.
– ui:repeat (facelets) doesn’t work
– a4j:repeat (richfaces) doesn’t work
– c:forEach works..only in case it does not rely on a variable defined by a parent component (rich:dataTable for instance)

All above are pretty logical phenomena, as UIData relies on ordered data, and generally a Set is not ordered.

In my case I had to use a Set defined in the Hibernate (JPA) object (PersistentSet).
An important note: you should use a set in case the view order is of no matter to you.

The solution..is pretty simple. And I’ll suggest it to be a part of facelets/richfaces for the next version, unless of course there is some valid specific reason for it not to be.

1. Define your own UI component extending an existing repeater component. I used a4j:repeat (HtmlAjaxRepeat)
2. Override the metohd getDataModel
3. Define your component in your faces-config
4. create a custom facelets tag definition
5. Define a context-variable in web.xml pointing to the facelet tag definition.

Note: for use with JSP instead of Facelets, you should define a .tld and a Tag handler, which is not an ojbect of this post.

Now let’s see the steps in detail:

1,2. Here some code:

package com.myproject.components;
import java.util.ArrayList;
import java.util.Set;

import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import org.ajax4jsf.component.html.HtmlAjaxRepeat;
import org.ajax4jsf.model.SequenceDataModel;

public class UIIterator extends HtmlAjaxRepeat {

 @SuppressWarnings("unchecked")
 @Override
 protected DataModel getDataModel() {
 Object current = getValue();
 if(current instanceof Set){
 return new SequenceDataModel(new ListDataModel(
 new ArrayList((Set) current)));
 }
 return super.getDataModel();
 }
}

So, as we don’t care about the order of the elements, we just create a new ArrayList out of the Set. And we can now easily return the appropirate DataModel.

3. Add this to your faces-config. (I copied it from the a4j definition)

<component>
 <description />
 <display-name>Iterator</display-name>
 <component-type>com.myproject.Iterator</component-type>
 <component-class>com.myproject.components.UIIterator</component-class>

 <component-extension>
 <component-family>javax.faces.Data</component-family>
 <renderer-type>org.ajax4jsf.components.RepeatRenderera</renderer-type>
 </component-extension>
 </component>

4. Here is the tag definition for facelets

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib xmlns="http://java.sun.com/JSF/Facelet">
<namespace>http://myproject.com/cust</namespace>

<tag>
<tag-name>repeat</tag-name>
<component>
<component-type>com.myproject.Iterator</component-type>
<renderer-type>org.ajax4jsf.components.RepeatRenderer</renderer-type>
</component>
</tag>

</facelet-taglib>

Save this file as /WEB-INF/facelets/custom.taglib.xml

5. Add to your web.xml

<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/custom.taglib.xml</param-value>
</context-param>

6. It is now ready to use

...
xmlns:cust="http://myproject.com/cust"
...

<cust:repeat var="myVar" value="${aSet}">
...
</cust:repeat>

I think it is way neater than other workarounds, like defining a custom EL Resolver.

Share Button

27 thoughts on “How to Iterate Over java.util.Set in JSF”

  1. Hi,

    yes sorry but my code snippet was not posted:

    I implemented exactly the same you did here. No I integrated this into a JSF page and I have the following:

    I have a user bean containing several roles (this is the set) and I use rich:dataList for iterating over the users. Now inside the rich:datalist I use the cust:repeat using the roles attribute as value. Now I am using a h:outputText for printing out the var: myVar and I do not get any data on the screen. But the data is inside the loaded object.

  2. If you want to use the iteration on rich:dataList, you must extend HtmlDataList instead of HtmlAjaxRepeat

  3. (the code wasn’t send)
    There’s an easier way.
    c:forEach var=”element_” items=”#{anyObject.elements}”
    c:set var=”element” value=”#{element_}” scope=”request”/
    h:outputText value=”#{element.description} “/
    /c:forEach

  4. Your tag handler code could be made more generic to accept not only Set, but all of Collection (I also added a type so you can drop the @SuppressWarnings annotation):

    ———————————————————-
    @Override
    protected DataModel getDataModel() {
    Object current = getValue();
    if (current instanceof Collection && !(current instanceof List)) {
    return new SequenceDataModel(
    new ListDataModel(
    new ArrayList(
    (Collection) current
    )
    )
    );
    }
    return super.getDataModel();
    }
    ———————————————————-

  5. Hi Bozho,
    Congratulations for the great article. In RichFaces 4 the class of the a4j:repeat component is org.richfaces.component.UIRepeat, which hasn’t got method getDataModel(). Is there any new solution for RichFaces 4?

  6. How strange that I find a 3 year old article and about something I need to solve today, and the writer has actually commented on it only yesterday! Incredible.

    I’m trying to do this with a datable which component will I need to extend?

  7. Hi Glen, it depends on which datatable you want to use, but components are usually called UIXX. For example: UIDataTable.

    But if it’s used in only a couple of places, you can make a new List based on the Set in your managed bean and pass that to the datatable.

  8. HI, with Struts nested tag, we can edit the content of collection and send back to action. How can we do this in JSF. Can any one help me Please.

  9. This is the perfect webpage for anybody who
    hopes to understand this topic. You know so much
    its almost tough to argue with you (not that I personally will need to…HaHa).

    You definitely put a new spin on a topic that
    has been discussed for years. Great stuff,
    just excellent!

  10. Everyone loves what you guys tend to be up too. This type of clever work and exposure!

    Keep up the great works guys I’ve incorporated you guys to blogroll.

  11. A motivating discussion is worth comment. I think that you ought to write more on this subject
    matter, it might not be a taboo subject but usually people do not talk about these issues.
    To the next! Best wishes!!

  12. I’m not sure the place you’re getting your information, but
    great topic. I must spend a while studying much more or understanding more.

    Thanks for great info I used to be in search of this info for my mission.

Leave a Reply

Your email address will not be published. Required fields are marked *