2

ボタンがバッキング 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)

顔-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 "";
}

この提案を読んで、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(...)`

だから私の質問は:

  1. Bean が Serializable を実装しているにもかかわらず、なぜ NotSerializableException が発生するのですか?

  2. Bean のサブセットのみに SERIALIZE_STATE_IN_SESSION パラメータを適用する方法はありますか?

  3. ビュー スコープ Bean を機能させる別の解決策はありますか (リクエスト スコープなどに変更する必要はありません)。

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

4

1 に答える 1

4

Bean が Serializable を実装しているにもかかわらず、なぜ NotSerializableException が発生するのですか?

Bean がシリアライズ可能である必要があるだけでなく、そのすべてのプロパティ (およびネストされたすべてのプロパティなど) もシリアライズ可能である必要があります。問題のあるシリアル化不可能なクラスの名前は、例外メッセージで簡単に見つけることができます。

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

<h:inputText>これは、以下のようにコンポーネントを Bean にバインドしていることを示唆しています。

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

Bean がリクエストスコープにない場合、これは実際には違法です。UIComponentインスタンスはリクエスト スコープであり、複数のリクエスト間で共有することはできません。さらに、UIComponentインスタンスはシリアライズできません。それらの状態だけですが、JSF はそれだけでそれを心配します。

プロパティを削除するfooInput必要があり、ビュー スコープの Bean にコンポーネントをバインドすることが正しい解決策であると誤って考えていた問題の別の解決策を探す必要があります。

  • ビューの他の場所にアクセスする場合#{bean.fooInput.value}は、Bean プロパティを必要とせずに Facelet スコープにバインドします。

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

    を介して、同じビュー内の別の場所で使用できます#{fooInput.xxx}

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

  • fooInput.setStyleClass("someClass")または など、Bean 内でプログラムによってコンポーネント属性を設定する場合はfooInput.setDisabled(true)、コンポーネント全体ではなくビューで特定の属性をバインドする必要があります。

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

  • UIComponentなんらかの理由で Bean 内のインスタンス全体を取得する必要があると確信している場合は、バインドする代わりに、メソッド ローカル スコープで手動で取得します。

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

    ただし、バッキング Bean のコンポーネント全体を取得する必要なく、具体的な問題を別の方法で解決する方法について質問するか、回答を検索することをお勧めします。

以下も参照してください。


に関しては、これにはjavax.faces.application.ViewExpiredException: View could not be RestoreViewExpiredExceptionでさらに詳しく説明されているさまざまな根拠があります。

于 2015-07-18T08:52:26.853 に答える