简体   繁体   中英

Can't access lazy annotated but initialized hibernate collection from JSF2

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    

}

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. Eg

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM