查看范围:java.io.NotSerializableException: javax.faces.component.html.HtmlInputText

Posted

技术标签:

【中文标题】查看范围:java.io.NotSerializableException: javax.faces.component.html.HtmlInputText【英文标题】:View scope: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText 【发布时间】:2015-10-07 18:27:37 【问题描述】:

每次按钮从 backing-bean 调用动作时都会出错。 仅适用于具有视图范围的 bean,我还没有找到一种方法来修复它而不回归代码中的其他模块。

DefaultFacele E   Exiting serializeView - Could not serialize state: javax.faces.component.html.HtmlInputText 
java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)

也可以:

com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0014E: Uncaught service() exception 
root cause Faces Servlet: ServletException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier /jspFiles/jsf/Deployments/editQueue.faces 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:205) 
Caused by: javax.faces.application.ViewExpiredException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier:  /jspFiles/jsf/Deployments/editQueue.faces
    at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute (RestoreViewExecutor.java:128)

faces-config.xml

<managed-bean>
  <managed-bean-name>pc_EditQueue</managed-bean-name>
  <managed-bean-class>pagecode.jspFiles.jsf.deployments.EditQueue</managed-bean-class>
  <managed-bean-scope>view</managed-bean-scope>
  <managed-property>
    <property-name>queueDeploymentBean</property-name>
    <value>#queueDeploymentBean</value>
  </managed-property>
</managed-bean>

web.xml

<context-param>
  <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  <param-value>server</param-value>
</context-param>
<context-param>
  <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
  <param-value>true</param-value>
</context-param>

豆子:

@ManagedBean
@ViewScoped
public class EditQueue extends PageCodeBase implements Serializable 
  private static final long serialVersionUID = -1L;
  public String doButtonAddAction() 
    // calls manager (long)
    FacesUtil.setViewMapValue("queueDeploymentBean", queueDeploymentBean);
    return "";

我阅读了这个suggestion 将SERIALIZE_STATE_IN_SESSION 设置为false,并且确实这个解决方案适用于这个视图范围bean。然而,这个修复代价高昂:应用程序中的许多现有模块不再工作,所以我不能在那里使用这个修复。观察到的一些回归是:

// returns null must be changed with FacesUtil.getSessionMapValue("userId"); 
getSessionScope().get("userId");`

// returns null must be changed with FacesUtil.getViewMapValue("linkerBean");
linkerBean = (Linker) getManagedBean("linkerBean");`

// NPE so must be changed with FacesContext.getCurrentInstance().addMessage(...)
getFacesContext().addMessage(...)`

所以我的问题是:

    为什么即使 bean 实现了 Serializable 也会出现 NotSerializableException ?

    有没有办法将 SERIALIZE_STATE_IN_SESSION 参数仅应用于 bean 的一个子集?

    是否有另一种解决方案让我的视图范围 bean 工作(无需将它们更改为请求范围或其他)?

    WebSphere 8.0.0.3, Java 1.6.0, JSF 2.0, RichFaces 4.2.3.Final

【问题讨论】:

【参考方案1】:

为什么即使 bean 实现了 Serializable 也会出现 NotSerializableException ?

不仅 bean 需要是可序列化的,它的所有属性(以及它们所有的嵌套属性等)也必须是可序列化的。在异常消息中很容易找到有问题的不可序列化类的名称:

java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)

这表明您正在将 &lt;h:inputText&gt; 组件绑定到 bean,如下所示:

<h:inputText binding="#bean.fooInput" ...>
private UIComponent fooInput;

当 bean 不在请求范围内时,这确实是非法的。 UIComponent 实例是请求范围的,不能在多个请求之间共享。此外,UIComponent 实例不可可序列化。只有他们的状态是,但 JSF 会自己担心这一切。

您必须删除fooInput 属性,并且您需要为您错误地认为将组件绑定到视图范围的bean 将是正确的解决方案的问题寻找不同的解决方案。

如果您打算在视图的其他位置访问它,例如#bean.fooInput.value,然后只需将其绑定到 Facelet 范围,而不需要 bean 属性:

<h:inputText binding="#fooInput" ...>

它将通过#fooInput.xxx在同一视图的其他地方提供。

<h:inputText ... required="#empty fooInput.value" />

如果您打算在 bean 中以编程方式设置某些组件属性,例如fooInput.setStyleClass("someClass"),或fooInput.setDisabled(true),那么你应该绑定视图中的特定属性而不是整个组件:

<h:inputText ... styleClass="#bean.styleClass" />
...
<h:inputText ... disabled="#bean.disabled" />

如果您非常肯定无论出于何种原因都需要在 bean 中获取整个 UIComponent 实例,那么请在方法本地范围内手动抓取它,而不是绑定它:

public void someMethod() 
    UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
    UIComponent fooInput = view.findComponent("formId:fooInputId");
    // ...

但最好提出问题或寻找答案,如何以不同的方式解决具体问题,而无需在支持 bean 中获取整个组件。

另见:

How does the 'binding' attribute work in JSF? When and how should it be used?

至于ViewExpiredException,这有不同的理由,在javax.faces.application.ViewExpiredException: View could not be restored中进一步阐述。

【讨论】:

以上是关于查看范围:java.io.NotSerializableException: javax.faces.component.html.HtmlInputText的主要内容,如果未能解决你的问题,请参考以下文章

如何查看SAP不同类型凭证编号的范围

地图上查看距离范围(百度地图)

如何在 Chrome 开发者工具中查看范围输入拇指的样式?

如何查看在 Windows 上保留临时端口范围的内容?

Linux 查看 && 修改端口范围限制

drupal 8 查看日期范围过滤器-“介于”运算符不包括结束日期