views:

20

answers:

1

I have JSF application with trinidad components and JAXB/JPA entity beans generated by Hyperjaxb3. In the UI I use Trinidad combo box component that has JPA object as values.

The scenario is:

  1. User make selection in combo box
  2. User clicks on a control that sends request to the server and is returned to the same form
  3. Data from the form was submitted and selection in combo box should be as user did in the step 1. equals() method is called on combo box items (JPA objects) and this exception is thrown:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: package.AnObject.items, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

 at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)

 at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)

 at org.jvnet.hyperjaxb3.item.AbstractItemList.size(AbstractItemList.java:51)

 at java.util.AbstractList$Itr.hasNext(Unknown Source)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:57)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:29)

 at package.AnObject.equals(AnObject.java:177)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:34)

 at package.ParentObject.equals(ParentObject.java:532)

 at package.ParentObject.equals(ParentObject.java:551)

 at java.util.ArrayList.indexOf(Unknown Source)

 at org.apache.myfaces.trinidad.component.UIXSelectMany._destructiveCompareOutOfOrderLists(UIXSelectMany.java:179)

 at org.apache.myfaces.trinidad.component.UIXSelectMany.compareValues(UIXSelectMany.java:139)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.validate(UIXEditableValue.java:180)

 at org.apache.myfaces.trinidad.component.UIXEditableValue._executeValidate(UIXEditableValue.java:503)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.processValidators(UIXEditableValue.java:270)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

I use OpenEntityManagerInViewFilter from Spring to get lazy loaded objects - that works in one request.

On the level of HyperJAXB generated object equals() method calls equals(Object object, EqualsBuilder equalsBuilder) method where equalsBuilder.append(...) is called on each attribute of that object. When that attribute is a list it is proxied by PersistenBag and that is the point where I get the LazyInitializationException.

equals() method - generated by HyperJaxb:

public boolean equals(Object object) {
    if (!(object instanceof ParentObject)) {
        return false;
    }
    if (this == object) {
        return true;
    }
    final EqualsBuilder equalsBuilder = new JAXBEqualsBuilder();
    equals(object, equalsBuilder);
    return equalsBuilder.isEquals();
}

equals(Object object, EqualsBuilder equalsBuilder) generated by HyperJaxb:

public void equals(Object object, EqualsBuilder equalsBuilder) {
    if (!(object instanceof ParentObject)) {
        equalsBuilder.appendSuper(false);
        return ;
    }
    if (this == object) {
        return ;
    }
    final ParentObjectthat = ((ParentObject) object);
    // PersitentBag, LazyInitializationException is thrown here
    equalsBuilder.append(this.getAnObject(), that.getAnObject());
    equalsBuilder.append(this.get..., that.get...);
    ...
}

Do you guys have any ideas how fix this problem?

I tried to use JSF converter and have SelectItem with a String value (not object) but if I remember right equals() is called after String is converted to my object.

A: 

You get this because your objects are not detached (1) and you access data (2) outside the session (3). To correct, you should address (1-3) in any combination.

  1. Detach your objects. This is probably the easiest, but it's no lazy loading.
  2. Make sure the session is available. You say you're using OEMIV pattern - how comes that the session isn't there when the equals method is called? I believe it's because equals is called not during the view rendering but in some other JSF phases. You can try to extend the OEMIV pattern to make it span over the whole JSF lifecycle.
  3. Don't access the data. equals(...) and hashCode(...) methods are recommended, but not required. You can disable their generation in HJ3, you can exclude certain properties from hashCode()/equals(...) building, you can use your own equals and hashCode strategies - plenty of ways to achieve this.

Me personally, I'd check first, why is the session not there.

lexicore
ps. Feel free to post your questions to [email protected].
lexicore