使用Primefaces的pf:selectCheckboxMenu控件抛LazyInitializationException异常
Posted on: 2015-01-23, Last modified: 2015-07-31, View: 3300

页面使用<pf:selectCheckboxMenu>控件多选值时,新建对象没有问题,编辑时一直报LazyInitializationException异常:

信息: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session
org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)

通过一步步调试跟踪源代码,发现问题:

1、当有ajax提交时就抛出这个异常,排除后台自编代码的问题;

2、跟踪JSF代码发现是validatior的时候出错

3、进一步调试代码发现是jsf的问题,其中有个MenuRender类会判断数据源的类型,如果是Collection类型的话,要调用其Add方法,进一步调用write()方法,会检查当前session然后取数据源的值,这个时候因为我们用的ViewBean,session早已失效,就会抛出这个异常。具体方法可以查看com.sun.faces.renderkit.html_basic.MenuRenderer类的convertSelectManyValuesForModel()方法。

if (modelType.isArray()) {
            return convertSelectManyValues(context,
                                           uiSelectMany,
                                           modelType,
                                           newValues);
        } else if (Collection.class.isAssignableFrom(modelType)) {
...
targetCollection.add(v);
...
}

 

if ( session == null ) {
      if ( allowLoadOutsideTransaction ) {
          session = openTemporarySessionForLoading();
          isTempSession = true;
      }
      else {
          throwLazyInitializationException( "could not initialize proxy - no Session" );
      }
 }

解决方案:

1、刚开始想着提交新值时不做validation可以解决问题,就试着加上了immediate = true,结果不好使。调试的时候发现不管immediate的值是true还是false, validate()方法竟然都在执行,UiiNput类里processDecodes()方法在immediate = true时候调用validate,processValidators()方法里当immediate = false时调用validate(),没有办法只能放弃这个打算;

2、查看PrimeFaces官方的demo,发现他在使用<pf:selectCheckboxMenu>控件时选中值并不是用的Colection结构,而是用的array。再回到convertSelectManyValuesForModel()方法发现原来在选中值的类型是array时不会有Collection类型add方法的问题,也就是不会牵扯到Session的失效与否,接着把选中值改成Array果然解决问题。

感觉PrimeFaces肯定也是发现了这个问题,没有好的解决方案只能使用Array来记录选中值绕过这个问题,使用的时候只能跟着一起走,问题解决不进一步深究,希望以后的Primefaces版本中能够解决这个问题。

 

Go
Friend Links:
Sonft