Blog

Friday, 1 February 2013

JSF, ManyToMany and LazyInitializationException


Recently I needed to create simple CRUD.
When I tried to modify collection of available entities with annotation @ManyToMany my application thr
ew failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: (…)”

Entities:
...

@Entity
@Table(name = "DISEASE")
public class Disease implements Serializable {
    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    @Length(max = 100)
    @Column(name = "NAME", length = 100, nullable = false)
    private String name;

    @NotNull
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
    private List<Symptom> symptoms = new ArrayList<Symptom>();

...
...

@Entity
@Table(name = "SYMPTOM")
public class Symptom implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    @Length(max = 100)
    @Column(name = "NAME", length = 100, nullable = false)
    private String name;

...


My facelet code:

...   

                
      
            
            
               
     
...

And stack trace error:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
 at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:393)
 at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:385)
 at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:378)
 at org.hibernate.collection.internal.AbstractPersistentCollection.write(AbstractPersistentCollection.java:208)
 at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:291)
 at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel(MenuRenderer.java:382)
 at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValue(MenuRenderer.java:129)
 at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:315)
 at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
 at javax.faces.component.UIInput.validate(UIInput.java:960)
 at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
 at javax.faces.component.UIInput.processValidators(UIInput.java:698)
 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
 at javax.faces.component.UIForm.processValidators(UIForm.java:253)
 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
 at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
 at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
 at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
 at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
 at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
 at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50)
 at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
 at java.lang.Thread.run(Thread.java:662)

At first I thought it was caused by FetchType attribute in my entity so I set “fetch = FetchType.EAGER”, but this didn’t help. In stack trace we can see that method when error occurred is called getConvertedValue() from MenuRendered class (from jsf-impl-2.1.7-jbossorg-2.jar). I needed to add Jboss Nexus repository to Maven settings file (settings.xml) and next downloaded sources and documentation to maven.
Then I could see exactly what caused the error:


...

    protected Object convertSelectManyValuesForModel(FacesContext context,
                                                     UISelectMany uiSelectMany,
                                                     Class modelType,
                                                     String[] newValues) {

        if (modelType.isArray()) {
            return convertSelectManyValues(context,
                                           uiSelectMany,
                                           modelType,
                                           newValues);
        } else if (Collection.class.isAssignableFrom(modelType)) {
            Object[] values = (Object[]) convertSelectManyValues(context,
                                                                 uiSelectMany,
                                                                 Object[].class,
                                                                 newValues);

            Collection targetCollection = null;

            // see if the collectionType hint is available, if so, use that
            Object collectionTypeHint = uiSelectMany.getAttributes().get("collectionType");
            if (collectionTypeHint != null) {
                targetCollection = createCollectionFromHint(collectionTypeHint);
            } else {
                // try to get a new Collection to store the values based
                // by trying to create a clone
                Collection currentValue = (Collection) uiSelectMany.getValue();
                if (currentValue != null) {
                    targetCollection = cloneValue(currentValue);
                }

    ...

Problem was that jsf tried to clone collection (line 30).

Solution was simple, I had to set attribute collectionType in selectManyCheckbox component to “java.util.ArrayList”:



  
                    
                

Alternatively it could be done like this:


 
                    

                


5 comments:

  1. Hey, thanks! it was helpful, by the way...
    the correct second solution is:


                        



                    




    the need to the inside the , not inside the

    Thanks again!

    ReplyDelete
  2. Thank you for posting this.

    One note: I think you meant to put

    collectionType and not collectiontype

    in our h:selectManyCheckbox

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Yes, on-line casino gamers win real cash on on-line slots games on a regular basis}. As long as you be a part of real cash on-line casinos or obtain real cash slots apps, find a way to|you possibly can} potentially win real cash. Welcome bonuses reward gamers after they make their first real cash deposit. The actual terms and requirements differ from casino to casino and some provides that appear too good to be true 돈포차 in all probability shall be. Before you commit your cash, we advocate checking the wagering requirements of the net slots casino you're planning to play at. These will clarify how a lot of your cash you're required to deposit upfront, and what find a way to|you possibly can} count on to receive in return.

    ReplyDelete