15

I have a question about outputing a list of objects as a comma separated list in JSF.

Let's say:

public class SomeObj {
  private String name;
  ... constructors, getters and setters ...
}

and List<SomeObj>:

List<SomeObj> lst = new ArrayList<SomeObj>();
lst.add(new SomeObj("NameA"));
lst.add(new SomeObj("NameB"));
lst.add(new SomeObj("NameC"));

to output it as a listbox I can use this code:

<h:selectManyListbox id="id1"
                  value="#{listHolder.selectedList}">
  <s:selectItems value="#{listHolder.lst}"
                   var="someObj"
                 label="#{someObj.name}"/>
  <s:convertEntity />
</h:selectManyListbox>

But what is the easiest way to output the list as is, comma seperated ? Like this:

NameA, NameB, NameC

Should I use JSTL <c:forEach/> or may be the <s:selectItems/> tag can also be used ?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
m_vitaly
  • 11,856
  • 5
  • 47
  • 63
  • 3
    Don't tag `jsp` if you're using `facelets`. Those are two entirely distinct view technologies, Facelets being less or more the successor of JSP when talking in JSF context. I've retagged accordingly. – BalusC Jul 13 '10 at 21:06

3 Answers3

26

Given a List<Person> persons where Person has a name property,

  • If you're already on Java EE 7 with EL 3.0, then use EL stream API.

    #{bean.persons.stream().map(p -> p.name).reduce((p1, p2) -> p1 += ', ' += p2).get()}
    
  • If you're not on EL 3.0 yet, but have JSF 2.x at hands, then use Facelets <ui:repeat>.

    <ui:repeat value="#{bean.persons}" var="person" varStatus="loop">
        #{person.name}#{not loop.last ? ', ' : ''}
    </ui:repeat>
    
  • Or if you're still on jurassic JSP, use JSTL <c:forEach>.

    <c:forEach items="#{bean.persons}" var="person" varStatus="loop">
        ${person.name}${not loop.last ? ', ' : ''}
    </c:forEach>
    

See also:

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Am I correct in that this requires JSF 2.0, i.e. varStatus is not supported for JSF 1.2 with facelets? – meriton Feb 22 '11 at 18:53
  • @meriton: Yes, you're correct. The `c:forEach` should however work by `xmlns:c="http://java.sun.com/jsp/jstl/core"`. – BalusC Feb 22 '11 at 19:11
  • Thanks for the confirmation. Being a tag handler, c:forEach won't work for me, since the number of repetitions changes after the view is constructed. But I found another way (which I added as answer). – meriton Feb 22 '11 at 19:36
  • @meriton: nice one! Yes, I should have added that JSTL only runs at view build time. – BalusC Feb 22 '11 at 19:37
  • Awesome. A lambda string joiner in one line for JSF EL... As usual, crazy stuff coming from BalusC is rather rare. – Kawu May 31 '19 at 17:16
7

use <ui:repeat> (from facelets). It's similar to c:forEach

Or pre-compute the comma-separated string in the managed bean, and obtain it via a getter.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
5

If you can't use varStatus because you're stuck with using JSF 1.2, you can do:

<ui:repeat value="#{listHolder.lst}" var="someObj">#{someObj != listHolder.lst[0] ? ',' : ''}
#{someObj.name}</ui:repeat>

The absence of whitespace around the EL-expressions is deliberate, we don't want a space to appear there in the rendered HTML.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • I think it should be: `#{someObj != listHolder.lst[listHolder.lst.size()-1] ? ',' : ''} #{someObj.name}` – t.olev Jan 06 '17 at 15:52