Avoiding LazyInitializationException on JSF selectManyMenu

Goal

We have a JPA persisted collection that we want to manage using a JSF selectManyMenu component successfully

Description

This last week, I had the need to implement a page containing a selectManyMenu component. Everything was working great until the moment that I started getting a LazyInitializationException anytime I was trying to save the data.

Unlike the usual lazy initialization problems I had faced before, this one was not “directly” related to a non eagerly loaded relation but with what happens inside method convertSelectManyValuesForModel() from class com.sun.faces.renderkit.html_basic.MenuRenderer.

How to

As you may know, LazyInitializationException is thrown anytime we try access to a relation that was not initialized during the moment that our persistence context/session was opened. However, in my specific scenario, that was not the case because it was an element collection relation and it was specified as eager (eager or lazy didn’t really matter, actually!). Besides, the problem was being triggered from the class com.sun.faces.renderkit.html_basic.MenuRenderer in the method convertSelectManyValuesForModel(), line 381 where we find the following line: (I am using JBoss AS 7.2 where the specific version of the JSF implementation is 2.1.18), during the JSF validation phase:

targetCollection.add(v);

Through code analysis, I realized that the problem was exactly in the fact that this class was creating a new collection not from my persistent property type (java.util.List, particularly something like java.util.ArrayList) but from the actual type loaded into that attribute which was a PersistentBag, initialized from my JPA provider implementation (in this case, Hibernate), created outside an open persistence context or session, leading to the thrown exception referred before at the time the selected elements in my component were being added. Additionally, I noticed that this code tried its best to create the appropriate collection, namely through the attribute collectionType, when specified in the selectManyMenu component:

...
// PZ: the problem is that the following check returns null
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
  // PZ: the following initializes a "closed" collection of type PersistentBag
  Collection currentValue = (Collection) uiSelectMany.getValue();
  if (currentValue != null) {
    targetCollection = cloneValue(currentValue);
  }
  // No cloned instance so if the modelType happens to represent a
  // concrete type (probably not the norm) try to reflect a
  // no-argument constructor and invoke if available.
  if (targetCollection == null) {
    //noinspection unchecked
    targetCollection = createCollection(currentValue, modelType);
  }
  // No suitable instance to work with, make our best guess
  // based on the type.
  if (targetCollection == null) {
    //noinspection unchecked
    targetCollection = bestGuess(modelType, values.length);
  }
}
...

So, all I had to do was specify the property collectionType in my selectManyMenu component as java.util.ArrayList and the problem was gone forever. Next, I present my project’s code relevant parts. First, my page (by the way, the use of a converter, whose implementation is not shown here because it is not part of the solution to the lazy initialization problem – which was a mere implementation of a JSF converter for my enumeration – was required to make this work):

...
<h:selectManyMenu id="drivingSkills"
  collectionType="java.util.ArrayList"
  value="#{personalSkillsBean.drivingSkills}"
  converter="drivingLicenseConverter">
  <f:selectItems value="#{licenseTypes}" var="licenseType"
    itemLabel="#{bundleUtil.getValue('DrivingLicense.'.concat(licenseType.name))}"
    itemValue="#{licenseType}" />
</h:selectManyMenu>
...

Next, my JSF backing bean, which was implemented as a stateful EJB:

@Named("personalSkillsBean")
@Stateful
public class PersonalSkillsBean {
...
  private List drivingSkills;
  public List getDrivingSkills() {
    if (drivingSkills == null) {
      drivingSkills = new ArrayList();
    }
    return drivingSkills;
  }
}
...

Now, my JPA relation specification:

@ElementCollection
@Enumerated(EnumType.STRING)
@CollectionTable(name = "driving_skills")
@Column(name = "type")
private List drivingSkills;

And finally, the definition of the DrivingLicense enumeration:

public enum DrivingLicense {
  A1, 
  A,
  B,
  ...
}

Explanations

The solution has already been explained in this recipe description. But, to summarize things up, basically, the MenuRenderer class was creating a new PersistentBag class which was the one that my JPA provider (Hibernate, in this case) had initialized for my persistent relation. That bag, however, was not being created inside any open persistence context, which would result in an exception being thrown anytime an addition was attempted. Therefore, and because what we really wanted the renderer to create was an implementation class of my java.util.List attribute, all it was necessary was the specification of the collectionType class to the fully qualified name of a class that implements that interface, such as java.util.ArrayList in my selectManyMenu component.

15 comments

  1. Hi. i am facing problem with i.e if it is having values like ALL,IA,IB,IC,ID….., first time if we click on any value the valueChangeListener of thie not calling ,,,,if select any item then second time onwards listener is calling..but i want first time listener call please any body help me.

    .xhtml is:

    1. Hello. Excuse me but I guess you forgot to add something in your comment. With such a generic problem, I don’t think there’s a way for me to even try helping you. Can you provide more details, please?

      1. you can take any example with one listener …first time selecting any item in the selectManyMenu its listener not going to respond or fire,but same time selecting one other element in the same selectManyMenu that time onwards listener will calling nicely .pelase provide the solution for ….it should call first time selecting any item in the selectManyMenu component of icefaces.

      1. Hum, I wonder if the problem is somewhat related to the use of iceFaces. Can you use a simple h:selectManyMenu instead, to check how it goes?

    1. if i use h:selectManyMenu but not solved also,in my case i have to use compalsary so this time more problems will come please i want solution with

  2. Great Post! Thank you, i had the Problem with a selectManyCheckbox and had to add collectionType=”java.util.HashSet”. This works pefectly.

  3. Struggled with this problem for two days – saw your post – added the collectionType=”java.util.ArrayList” – all my problems are gone.
    From my heart; Thanks 🙂
    Carsten, Aarhus, Denmark

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s