为primefaces datalist实现LazyModel时出现异常

时间:2012-10-25 15:54:24

标签: spring jsf-2 primefaces pagination nullpointerexception

我正在尝试为primefaces datalist实现延迟加载模型,类似于数据表here

我使用普通AJAX分页功能的初始代码完全正常。但是,当我尝试使用延迟加载模型时,我在页面加载时得到以下异常:

com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error Rendering View[/pages/index.xhtml]
java.io.NotSerializableException: java.util.ArrayList$SubList
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at java.util.HashMap.writeObject(HashMap.java:1100)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:975)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1362)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1170)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at java.util.HashMap.writeObject(HashMap.java:1100)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:975)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at com.sun.faces.renderkit.ClientSideStateHelper.doWriteState(ClientSideStateHelper.java:325)
    at com.sun.faces.renderkit.ClientSideStateHelper.writeState(ClientSideStateHelper.java:173)
    at com.sun.faces.renderkit.ResponseStateManagerImpl.writeState(ResponseStateManagerImpl.java:122)
    at com.sun.faces.application.StateManagerImpl.writeState(StateManagerImpl.java:166)
    at com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:418)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

以下是 index.html

的代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:p="http://primefaces.org/ui">

<ui:composition template="/pages/templates/template.xhtml">
   <ui:define name="content">

      <h:form prependId="false" id="form">
         <p:dataList value="#{movies.lazyMovieModel}" var="movie" id="movies" paginator="true" rows="10"
            paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
            type="none" paginatorAlwaysVisible="false" lazy="true">

            <h:outputText value="#{movie.movieName}, #{movie.releaseYear}" style="margin-left:10px">
            </h:outputText>
            <br/>
         </p:dataList>
      </h:form>

   </ui:define>
</ui:composition>
</html>

MovieListBean.java

import org.primefaces.model.LazyDataModel;

import com.clixflix.enitities.Movie;
import com.clixflix.jsf.extensions.LazyMovieDataModel;

@ManagedBean(name = "movies")
@ViewScoped
public class MovieListBean extends BaseBean implements Serializable
{
   private static final long serialVersionUID = -5719443344065177588L;

   private LazyDataModel<Movie> lazyMovieModel;

   @PostConstruct
   public void initialize() {
      lazyMovieModel = new LazyMovieDataModel();
   }

   public LazyDataModel<Movie> getLazyMovieModel() 
   {
      List<Movie> movieList = getServiceLocator().getMovieService().getMovieList();
      ((LazyMovieDataModel) lazyMovieModel).setMovieList(movieList);
      return lazyMovieModel;
   }
}

LazyMovieDataModel.java (LazyModel实现)

public class LazyMovieDataModel extends LazyDataModel<Movie>
{
   private static final long serialVersionUID = 8745562148994455749L;

   private List<Movie> movieList;

   public LazyMovieDataModel() {
      this.movieList = Collections.emptyList();
   }

   @Override
   public List<Movie> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
      // Sorting
      if (null != sortField) {
         LazySorter sorter = new LazySorter(sortField, sortOrder);
         Collections.sort(movieList, sorter);
         sorter = null;
      }

      // RowCount
      int rowCount = movieList.size();
      this.setRowCount(rowCount);

      // Pagination
      if (rowCount > pageSize) {
         return movieList.subList(first, (first + pageSize));
      }
      else {
         return movieList;
      }
   }


   private class LazySorter implements Comparator<Movie>
   {
      private String sortField;

      private SortOrder sortOrder;

      LazySorter(String sortField, SortOrder sortOrder) {
         this.sortField = sortField;
         this.sortOrder = sortOrder;
      }

      @SuppressWarnings("unchecked")
      @Override
      public int compare(Movie movie1, Movie movie2) {
         Object value1 = null, value2 = null;

         try {
            value1 = Movie.class.getField(this.sortField).get(movie1);
            value2 = Movie.class.getField(this.sortField).get(movie2);

            int value = ((Comparable<Object>) value1).compareTo(value2);
            return SortOrder.ASCENDING.equals(sortOrder) ? value : -1 * value;
         }
         catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            e.printStackTrace();
            return 0;
         }
      }
   }

   public void setMovieList(List<Movie> movieList) {
      this.movieList = movieList;
   }
}

我假设异常就在这一行:

return movieList.subList(first, (first + pageSize));

有人可以指导一下我错过了什么吗?

另外,我在日志中观察到,当我使用lazymodel时,数据库被查询三次但是当我使用正常的AJAX分页时,数据库只被查询一次< / strong>:|


更新:我找出了数据库被查询3次的原因。这是因为我在LazyModel的getter中调用我的服务而不是仅在load方法中调用。

我在课程中做了以下更改:

LazyMovieDataModel.java

public class LazyMovieDataModel extends LazyDataModel<Movie>
{
   private static final long serialVersionUID = 8745562148994455749L;

   public LazyMovieDataModel() {}

   @Override
   public List<Movie> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {

      List<Movie> movieList = getServiceLocator().getMovieService().getMovieList(first, (first + pageSize));

      // RowCount
      int rowCount = ((Number)getServiceLocator().getMovieService().getMovieCount()).intValue();
      this.setRowCount(rowCount);
   }
}

MovieListBean.java中的LazyModel getter

/* Removed PostConstruct init method */

public LazyDataModel<Movie> getLazyMovieModel() 
{
   return lazyMovieModel;
}

以上更改在初始页面加载时工作正常。但是,当我点击下一页按钮(或任何分页按钮)时,我会在加载方法中获得getServiceLocator()的NPE。

serviceLocator是一个protected访问修改后的托管属性,继承自BaseBean并使用Spring注入。

getter在后续调用时返回null的任何原因???

2 个答案:

答案 0 :(得分:0)

ArrayList $ SubList是个问题。返回的subList没有实现serializable 尝试使用:

return new ArrayList(movieList.subList(first, (first + pageSize)));

答案 1 :(得分:0)

与此link中的问题相同。LazyDataModel中有2种加载方法:

// FormGroupName

constructor (@Optional() @Host() @SkipSelf() parent: ControlContainer,) {}

这是引发错误的地方。您正在使用多重排序,因此您应该覆盖第二个。默认方法是第一个。