primefaces: DataTable: Sort on ListTableModel fails with NPE

DataTable Sort on ListDataModel fails with NPE - WrappedData List lost after sort order has been changed. Using List instead of ListDataModel works.

Environment:

  • PF Version: 10.0.0-SNAPSHOT
  • JSF + version: Mojarra 2.3.14
  • Java Runtime: 11.0.9.1

Example Bean

@Named
@ViewScoped
public class TestView implements Serializable {

    private DataService dataService;
    private DataModel dataModel;

    public DataModel getDataModel() {
         if ( dataModel == null ) {
              dataModel = new ListDataModel<>( dataService.getData() );
         }
         return dataModel;
    }
}

Stacktrace

10:06:24,955 INFO  [javax.enterprise.resource.webcontainer.jsf.context] (default task-7) java.lang.NullPointerException: java.lang.NullPointerException
	at deployment.test-SNAPSHOT.war//org.primefaces.component.datatable.feature.SortFeature.sort(SortFeature.java:154)
	at deployment.test-SNAPSHOT.war//org.primefaces.component.datatable.feature.SortFeature.decode(SortFeature.java:107)
	at deployment.test-SNAPSHOT.war//org.primefaces.component.datatable.DataTableRenderer.decode(DataTableRenderer.java:72)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponentBase.decode(UIComponentBase.java:509)
	at deployment.test-SNAPSHOT.war//org.primefaces.component.api.UIData.processDecodes(UIData.java:117)
	at deployment.test-SNAPSHOT.war//com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:606)
	at deployment.test-SNAPSHOT.war//com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:159)
	at deployment.test-SNAPSHOT.war//org.primefaces.component.api.UIData.visitTree(UIData.java:683)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponent.visitTree(UIComponent.java:1468)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponent.visitTree(UIComponent.java:1468)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponent.visitTree(UIComponent.java:1468)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIForm.visitTree(UIForm.java:355)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponent.visitTree(UIComponent.java:1468)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIComponent.visitTree(UIComponent.java:1468)
	at deployment.test-SNAPSHOT.war//com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:400)
	at deployment.test-SNAPSHOT.war//com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:261)
	at deployment.test-SNAPSHOT.war//org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:65)
	at deployment.test-SNAPSHOT.war//javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:1008)
	at deployment.test-SNAPSHOT.war//com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:55)
	at deployment.test-SNAPSHOT.war//com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
	at deployment.test-SNAPSHOT.war//com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177)
	at deployment.test-SNAPSHOT.war//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707)
	at deployment.test-SNAPSHOT.war//javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
<p:dataTable id="datatable" value="#{dataTable018.dataModel}" var="lang" paginator="true" rows="3"
                         filteredValue="#{dataTable018.filteredProgLanguages}" filterEvent="enter" rowKey="#{lang.id}" selectionMode="single"
                         paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                         rowsPerPageTemplate="2,3,5,10">
    <p:column headerText="ID" sortBy="#{lang.id}">
        <h:outputText value="#{lang.id}"/>
    </p:column>
    <p:column headerText="Name" sortBy="#{lang.name}" filterBy="#{lang.name}" filterMatchMode="contains">
        <h:outputText value="#{lang.name}"/>
    </p:column>
    <p:column headerText="First appeared" sortBy="#{lang.firstAppeared}" filterBy="#{lang.firstAppeared}" filterMatchMode="gte">
        <h:outputText value="#{lang.firstAppeared}"/>
    </p:column>
    <p:column headerText="OS" field="mainOs.nameShort"/>
</p:dataTable>

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 28 (21 by maintainers)

Commits related to this issue

Most upvoted comments

After some testing I discovered that the NPE on sorting only occurs if filtering is enabled for a column - it does not need to be the same column used for sorting.

After some debugging I identified the problem in method SelectionFeature.decode.

If the table has filtered values (it even has values if no filter entered) the DataTables value is set to null and restored with ‘originalValue’ after decodeSelection. This way the ValueExpression of the property is lost and replaced by a DataModel instance which seems to lead into a problem with the state of the component as in further sort requests getValue() returns an ListTableModel with a null list.

I solved the problem in SelectionFeature by replacing get/setValue() with get/setDataModel(). Maybe you might take a look on the applied patch.

An other circumstance that makes it difficult to reproduce the problem is that DataTable Features are not processed in a predictable order. As Features are stored in a HashMap, the order might change between application restarts - using a LinkedHashMap would help. sort_selectionfeature.patch.txt