【问题标题】:Prevent component tree serialization for certain parts of application防止应用程序某些部分的组件树序列化
【发布时间】:2011-01-04 12:41:29
【问题描述】:

是否可以明确拒绝 JSF 序列化某些组件树?目前我将一个不可序列化的对象传递给<h:inputText>

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

点击几下后我得到了(在视图恢复期间):

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

我认为这是因为 JSF 无法恢复 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)

一个额外的问题:可以不使支持 bean 可序列化吗?那么这是否应该阻止这些的序列化/反序列化?

一些背景:

我们有一堆需要在 JSF 中提供表单的 3rd 方类。问题是我们不能直接在 JSF 页面上使用这些类,因为它们没有实现 Serializable 接口,因此如果 JSF 运行时决定序列化/反序列化页面和组件树,将会/应该失败。这些类是“关闭的”,我们不能修改它们。

运行 Mojarra 2.0.2。

【问题讨论】:

  • the 页面和这些 类是什么意思?我不确定如何将 JSF 中的页面声明为可序列化。你能更明确一点吗,例如通过提供一些代码示例?
  • 对不起,我指的是支持豆。 JSF 中没有 pages 是正确的(尽管有 ViewRoot)。我的想法确实存在问题,我会更新问题以更好地反映问题。

标签: jsf serialization jsf-2


【解决方案1】:

Javabeans 是由 spec 实现的 Serializable。 JSF 只是遵循/遵守此规范。

这些类是“关闭的”,我们不能修改它们。

最好的办法是将其包装为实现Serializable 的类的transient 属性,并相应地实现writeObject()readObject()

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());
        // ...
    }

}

最后改用那个类。你最终可以让它extends NonSerializableClass,然后通过一个像样的IDE自动生成委托方法。

无论哪种方式,它只会是很多不透明和样板代码,但是由于您不允许修改这些类...(我个人只是推动那些 3rd 方的东西让它们拥有所谓的Javabeans 来实现Serializable,因为是他们破坏了标准/规范)。

【讨论】:

  • 这实际上正是我所做的 - 创建了一个 Serializable 包装类并按照您在此处显示的那样进行了自定义保存/恢复。问题是,我有很深的对象层次结构(呈现我们为其创建表单的数据),我必须遍历这些层次结构,将每个不可序列化的类映射到包装器等。确实有很多工作。但是你所说的“通过一个有点像样的 IDE 自动生成委托方法”是什么意思?
  • 不错的功能,很高兴知道未来!同时,我确实设法获得了少数有问题的类和 XML 模式的源代码,因此我使用implements Serializable 进行了新的 JAXB 转换。问题已解决。回到问题:一个简单的不能阻止某些属性的序列化(所以包含它们的bean)?如果这是不可能的,是否可以向 JSF 组件传递一个不在 bean 中的属性?我想这与 JSF 赖以生存的所有基础都背道而驰?
  • 我想这就是它,虽然它让我伤心:) 选择作为接受的答案...
【解决方案2】:

如果类成员(例如nonSerializableClassInstance)没有被序列化,我不知道你期望什么。 当然,您可以将它们标记为transient

托管 bean 的目的是保持应用程序状态 - 如果某些成员没有被序列化(如果服务器需要这样做),您将丢失状态。

【讨论】:

  • 我可以将它们标记为暂时的,但是我需要一些其他方法来恢复它们(在 bean 的状态恢复中)。然而,JSF 告诉我,我将不可序列化的类实例传递给了字段(例如,h:inputText)并且组件树无法恢复,我不知道该怎么做那里的自定义处理。此外,这些是第 3 方类,我不能只是让它们可序列化,这就是为什么不让 JSF 将这些树持久化到磁盘可能是最简单的。如果内存最终耗尽,我宁愿将用户重定向到错误页面(我们有足够的 RAM...)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 2019-09-09
相关资源
最近更新 更多