ここに示すように、データテーブルに似たプライムフェイスデータリストの遅延読み込みモデルを実装しようとしています。
通常の 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 を使用すると DB が3 回クエリされますが、通常の AJAX ページネーションを使用すると、DB は1 回だけクエリされます:|
更新: DB が 3 回クエリされる理由がわかりました。これは、ロード メソッドだけでなく、LazyModel のゲッターでサービスを呼び出していたためです。
クラスに次の変更を加えました。
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 ゲッター
/* Removed PostConstruct init method */
public LazyDataModel<Movie> getLazyMovieModel()
{
return lazyMovieModel;
}
上記の変更は、最初のページの読み込み時に正常に機能します。ただし、次のページ ボタン (またはページネーション ボタン) を押すgetServiceLocator()
と、load メソッドで NPE が発生します。
serviceLocator は、protected
BaseBean から継承され、Spring を使用して注入されたアクセス変更管理プロパティです。
ゲッターが後続の呼び出しで null を返す理由は何か???