2

I have a many-to-many relationship between the two entities called events and artists, both are annotated to be lazy loaded. When I load an artist, I initialize its events because the session will be closed afterwards using

Hibernate.initialize(artist.getEvents());

A test in pure Java works fine and I can access the events and its properties afterwards.

But in the .xhtml page presenting the result, I can only access the artist's properties and test if there are any events available, Artist is the backing bean, getData() returns the Artist, the following line still works:

<h:outputText value="No events available" rendered="#{empty artist.data.events}"/>

But when I want to access the properties of the events in a dataTable using

<h:dataTable value="#{artist.data.events}" var="event" rendered="#{not empty artist.data.events}">
  <h:column>
    <h:outputText value="#{event.title}"/>
  </h:column>
</h:dataTable>

I get the followig exception:

/artist.xhtml @48,63 value="#{event.title}": The class 'org.hibernate.collection.PersistentSet' does not have the property 'title'.

My first thought was that Hibernate's initialize method does not work together with JSF2, but event when I change the FetchType from LAZY to EAGER I end up getting the same result.

The Event class looks like this, for brevity I only included the parts relevant to the title property:

@Entity()
@Table(name="Events")
@SequenceGenerator(name="events_id", sequenceName="event_seq", initialValue=1, allocationSize=1)
public class EventData implements Serializable {

    private String title;
    // other private variables

    public EventData() {}

    public EventData(String title, ...) {
        this.title = title;
        // ...
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    // other setters/getters, equals/getHashCode overrides    

}
hro
  • 23
  • 1
  • 4

2 Answers2

6

UIData components can only iterate over an T[], List<E> or a DataModel<E>, not over a Set<E> because there's no way to identify an element in a Set<E> by an index, while it is required in UIData components.

@Bozho has written a weblog describing one way how to go around it. Other ways are to configure JPA to use List<E> instead or to add a getter which wraps it in a List<E> or DataModel<E> and use it instead in UIData component. E.g.

public DataModel<Event> getEventModel() {
    return new ArrayDataModel<Event>(events.toArray(new Event[events.size()]));
}

This by the way uses the same instances (doesn't copy/clone/recreate them), so all changes will be reflected in the right instances.


Update: in the upcoming JSF 2.2, the UIData will finally support Collection<E>, which thus includes Set<E>. Another way is to create a custom EL resolver as answered here: How do I use a java.util.Set with UIData in JSF. Specifically h:datatable?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • thanks for the exact answer BalusC, after I added a property events (List getEvents()) to my Artist backing Bean it worked! – hro Jul 11 '10 at 17:33
0

Voodoo is required to expose any bean to the #{...} facility. The simplest is to use CDI if your web container supports it, but otherwise look at the @ManagedBean annotation in JSF2.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • I have other xhtml pages accessing the Artist's properties just fine which is a @ManagedBean – hro Jul 11 '10 at 17:18