4

I have a primefaces dataList within a primefaces dataGrid but I'm having issue mapping to a property of the nested dataList collection (java.util.Set). When I reference any attribute on the nested Set (dream.tag), I get exception:

javax.servlet.ServletException: /registered/modify.xhtml @42,48 value="#{tag.id}": Property 'id' not found on type org.hibernate.collection.PersistentSet.

That attribute is there, but the dream.tag attribute is mapped to a private Set tag. Is it possible to use the dataList component with a Set. I've copied an outline of my data model below. Thanks for the help!

<p:dataGrid var="dream" value="#{dreamModifyBean.dreams}" columns="5"  rows="10" paginator="true" effect="true"  paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" rowsPerPageTemplate="10,15,20" paginatorPosition="bottom"> 
    <p:column>  
        <h:panelGrid columns="1" style="width:100%"> 
            <h:outputText value="#{dream.order}. #{dream.title}"/><br/>
            <p:graphicImage value="#{dream.imageThumb}" width="125" height="100"/><br/>
            <h:outputText value="#{dream.notes}"/><br/>
            <p:dataList value="#{dream.tag}" var="tag">  
                <h:outputText value="#{tag.id}"/>
            </p:dataList> 
            <h:outputText value="#{bundle['dreamModify.cost.TEXT']} #{dream.cost}"/><br/>
        </h:panelGrid>  
    </p:column>  
</p:dataGrid>

Dream (dreamModifyBean.dreams) - Parent:

public class Dream implements Serializable{
 @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
 @JoinColumn(name="DREAM_ID")
 private Set<Tag> tag;

public Set<Tag> getTag() {
    return tag;
}
public void setTag(Set<Tag> tag) {
    this.tag = tag;
}
}

Tag (dream.tag) - Child

public class Tag {
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Basic(optional=false)
 @Column(name="ID")
 private Long id;
 @Basic(optional=false)
 @Column(name="DESCRIPTION")
 private String description;
 @ManyToOne(fetch=FetchType.EAGER)
 @JoinColumn(name="DREAM_ID")
 private Dream dream;

 public Long getId() {
    return id;
 }
 public void setId(Long id) {
    this.id = id;
 }
 public String getDescription() {
    return description;
 }
 public void setDescription(String description) {
    this.description = description;
 }
public Dream getDream() {
    return dream;
}
public void setDream(Dream dream) {
    this.dream = dream;
}
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
c12
  • 9,557
  • 48
  • 157
  • 253

3 Answers3

9

Try to use a List. The value attribute must be one of the following as described here:

  • a list of beans
  • an array of beans
  • a single bean
  • a javax.faces.model.DataModel object
  • a java.sql.ResultSet object
  • a javax.servlet.jsp.jstl.sql.Result object
  • a javax.sql.RowSet object
Matt Handy
  • 29,855
  • 2
  • 89
  • 112
  • 3
    Nice list. I would however like to stress that using the `ResultSet` and `RowSet` are poor practices (too much tight coupling of the view with DB model and prone to resource leaks). – BalusC Mar 31 '11 at 16:32
2

You can use toArray() method of the Set:

<p:dataList value="#{dream.tag.toArray}" var="tag">  
    <h:outputText value="#{tag.id}" />
</p:dataList>
Ahmet
  • 908
  • 1
  • 17
  • 26
1

I have exactly the same issue, and assume a bug in the primefaces implementation (it clearly states that it iterates over collections). BTW, it seems to fail while it renders the end tag, not the list itself.

A (not fully satisfying) workaround is to add a helper method:

public List<Tag> getTagsAsList() {
    return new ArrayList<Tag>(tags);
}

@Matt Handy: A Set can certainly be ordered, some implementations are (like TreeSet), others are not (like HashSet). The main difference between Set and List is the handling of duplicates.

Edit: I was too fast to blame Primefaces. Seems like the root of the problem lies in the JSF implementation itself, which is not providing a DataModel for Sets. See here for more details.

Jan Groth
  • 14,039
  • 5
  • 40
  • 55
  • I think if you want to rely on the ordering you have to use a List. Set/List issue has been discussed before. [See this question](http://stackoverflow.com/questions/1035008/what-is-the-difference-between-set-and-list). – Matt Handy Mar 30 '11 at 06:23
  • That is not correct in general (as some answers in the discussion you are linking to are also stating). To eliminate all doubts: Have a look at [TreeSet](http://download.oracle.com/javase/6/docs/api/java/util/TreeSet.html), it is a Set with a well-defined natural ordering, which you can very well rely on. – Jan Groth Mar 30 '11 at 06:51
  • As to blaming, a `Set` offers **no ways** to obtain elements by an index. This is simply mandatory for JSF in order to locate the right rows during apply request values, validations, update model values and invoke application phases whenever a form with a table is been submitted. – BalusC Mar 31 '11 at 16:33
  • `new ArrayList(Set )` would be a way ;-) Of course all assumptions about the order of elements are up to the implementation of the Set, but there might as well be usecases where a consistent ordering is not required. In my perception this would fill a gap between persistence (where sets are very useful) and presentation. – Jan Groth Apr 01 '11 at 06:00