1

Is it possible to explicitly deny JSF from serializing some component trees? At the moment I am passing a non-serializable object to a <h:inputText>:

<h:inputText value="#{nonSerializableBean.nonSerializableClassInstance}" />

What happens after a few clicks is that I get (during view restoration):

javax.faces.FacesException: Unexpected error restoring state for component
with id configurationForm:j_idt292:j_idt302:field.  Cause:
java.lang.IllegalStateException: java.lang.InstantiationException:
my.namespace.NonSerializableClass

I think this occurs because JSF cannot restore the nonSerializableClassInstance:

Caused by: java.lang.IllegalStateException: java.lang.InstantiationException: com.foobar.utils.text.Period
at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:110)
at javax.faces.component.ComponentStateHelper.restoreState(ComponentStateHelper.java:292)
at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1444)
at javax.faces.component.UIOutput.restoreState(UIOutput.java:255)
at javax.faces.component.UIInput.restoreState(UIInput.java:1359)

A bonus question: Is it ok not to make backing beans Serializable? Should this then prevent serialization/deserialization of these?

Some background:

We have a bunch of 3rd party classes that we need to provide forms for in JSF. The problem is that we cannot directly use these classes on JSF pages, because they do not implement Serializable interface, and thus will/should fail if JSF runtime decides to serialize/deserialize the page and the component-tree. The classes are "closed" and we are not allowed to modify them.

Running Mojarra 2.0.2.

Tiny
  • 27,221
  • 105
  • 339
  • 599
Tuukka Mustonen
  • 4,722
  • 9
  • 49
  • 79
  • 1
    What do you mean with *the* pages and *these* classes? I'm not sure how a page in JSF can be declared as being Serializable. Can you be a bit more explicit, e.g. by providing some code samples? – Arjan Tijms Jan 04 '11 at 20:35
  • Sorry, by page I mean the backing beans. You are correct that there are no *pages* in JSF (though there is the ViewRoot). I do have issues with my thoughts here, I'll update the question to better reflect the issue. – Tuukka Mustonen Jan 05 '11 at 08:33

2 Answers2

5

Javabeans are by spec supposed to implement Serializable. JSF just follows/adheres this spec.

The classes are "closed" and we are not allowed to modify them.

Your best bet is to wrap it as a transient property of a class which implements Serializable and implement the writeObject() and readObject() accordingly.

public class SerializableClass implements Serializable {

    private transient NonSerializableClass nonSerializableClass;

    public SerializableClass(NonSerializableClass nonSerializableClass) {
        this.nonSerializableClass = nonSerializableClass;
    }

    public NonSerializableClass getNonSerializableClass() {
        return nonSerializableClass;
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(nonSerializableClass.getProperty1());
        oos.writeObject(nonSerializableClass.getProperty2());
        // ...
    }

    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        nonSerializableClass = new NonSerializableClass();
        nonSerializableClass.setProperty1((String) ois.readObject());
        nonSerializableClass.setProperty2((String) ois.readObject());
        // ...
    }

}

Finally use that class instead. You could eventually let it extends NonSerializableClass and then autogenerate delegate methods by a bit decent IDE.

Either way, it's only going to be a lot of opaque and boilerplate code, but since you're not allowed to modify those classes... (I would personally just push that 3rd party stuff to have them their so-called Javabeans to implement Serializable since it are them who's breaking the standards/specs).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • This is actually exactly what I did - created a `Serializable` wrapper class and did custom save saving/restoring as you've shown here. The problem is, I have deep object hierarchies (that present the data we create forms for) and I would have to traverse through these hierarchies, mapping each non-serializable class into wrappers etc. etc. Lots of work indeed. But what do you mean by "autogenerate delegate methods by a bit decent IDE"? – Tuukka Mustonen Jan 06 '11 at 22:32
  • http://stackoverflow.com/questions/4546807/implementing-multiple-interfaces-with-java-is-there-a-way-to-delegate/4546871#4546871 – BalusC Jan 06 '11 at 23:02
  • Nice feature, good to know for the future! Meanwhile, I did manage to get the source code for the few problematic classes and XML schemas so I did a new JAXB conversion with `implements Serializable`. Issues resolved. Back to the question: one simple cannot prevent serialization of certain properties (so the beans that contain them)? If that is not possible, would it be possible to pass a JSF component a property that doesn't live in a bean? I guess this fights against all the foundations that JSF lives on? – Tuukka Mustonen Jan 07 '11 at 10:43
  • I guess this is it then although it makes me sad :) Selecting as accepted answer... – Tuukka Mustonen Jan 10 '11 at 15:00
1

I don't know what you expect if the class members (e.g. nonSerializableClassInstance) are not getting serialized. Of course, you can mark them as transient.

The aim of a managed bean is to hold the application state - you will lose the state if some members are not getting serialized (if the server has the need of doing this).

ppronair
  • 26
  • 2
  • I could mark them transient, but then I would need some other way to restore them (in bean's state restoration). Here however, *JSF* is telling me that I passed non-serializable class instances to fields (`h:inputText`, for example) and that the component tree cannot be restored and I don't know how I could do custom handling there. Also, these are 3rd party classes and I cannot just make them serializable, that's why it might be easiest just not to allow JSF persist these trees to disk. I would rather redirect user to an error page if the memory finally runs out (we have plenty of RAM...). – Tuukka Mustonen Jan 06 '11 at 02:25