joinfaces: Primefaces datatable with LazyDataModel is not working properly with spring session

The error occurs using Primefaces datatable component with LazyDataModel and Spring Session.

I built lazy example to describe it. More details about the error are at README.

I see that JoinFaces has SpringSessionFixFilter filter to enable integration between jsf and spring session. However, the error persists.

I look forward to your answer.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 32 (25 by maintainers)

Most upvoted comments

I think the problem is related to javax.faces.model.ListDataModel default constructor implementation:

  public ListDataModel() {
    this(null);
  }

It sets list attribute to null. It seems that default constructor is always called in deserialization. So, list value is lost from the data store.

This code affects org.primefaces.model.LazyDataModel implementation in primefaces 10. The 10 version uses list attribute when it overrides getWrappedData() from javax.faces.model.DataModel.

org.primefaces.model.LazyDataModel in 8 version is not affected because it does not use list attribute from javax.faces.model.DataModel. It uses own data attribute instead. That’s why 8 version is working.

I don’t know if it will happen with other serialization/deserialization mechanisms, but it is happening with spring session.

@persapiens is right with his analyzis. Here is a workaround (EDITED):

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import javax.faces.model.DataModelListener;
import org.primefaces.model.LazyDataModel;

/**
 * The org.primefaces.model.LazyDataModel has a deserialization problem as
 * of 10.0.0 
 * 
 * https://github.com/primefaces/primefaces/issues/7699 and
 * https://github.com/joinfaces/joinfaces/issues/1159
 * 
 * The problem is that on deserialization the default constructor on the first
 * non-serializable superclass (javax.faces.model.ListDataModel) is called,
 * which sets the list attribute (wrappedData) to null.
 * This class saves and restores it on serialization/deserialization and can
 * be used as drop-in replacement for LazyDataModel
 * @author Thomas Oster <thomas.oster@upstart-it.de>
 */
public abstract class LazyDataModelFixed<T> extends LazyDataModel<T> implements Serializable {

    private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException 
    {
        aInputStream.defaultReadObject();
        setWrappedData(aInputStream.readObject());
        setRowIndex(aInputStream.readInt());
        DataModelListener[] l = (DataModelListener[]) aInputStream.readObject();
        if (l != null) {
            for (DataModelListener li : l) {
                addDataModelListener(li);
            }
        }
    }
 
    private void writeObject(ObjectOutputStream aOutputStream) throws IOException {
        aOutputStream.defaultWriteObject();
        List wd = getWrappedData();
        if (wd != null) {
            //wrap in LinkedList because implementation may not be serializable
            wd = new LinkedList<>(wd);
        }
        aOutputStream.writeObject(wd);
        aOutputStream.writeInt(getRowIndex());
        aOutputStream.writeObject(getDataModelListeners());
    }
}

please provide a PR to restore the behavior, so we can check if all our tests are passing