Область видимости: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText

Каждый раз, когда кнопка вызывает действие из компонента поддержки, возникает ошибка. Применяется только к 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. почему NotSerializableException, хотя бин реализует Serializable?
  2. Есть ли способ применить параметр SERIALIZE_STATE_IN_SESSION только к подмножеству компонентов или нет?
  3. Есть ли другое решение, чтобы мой бин видимости работал (без необходимости изменять их, чтобы запросить область видимости или иначе)?

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

1 ответ

почему NotSerializableException, хотя бин реализует Serializable?

Не только бин должен быть сериализуемым, но все его свойства (и все их вложенные свойства и т. Д.) Также должны быть сериализуемыми. Имя нарушающего несериализуемого класса можно легко найти в сообщении об исключении:

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

Это говорит о том, что вы связываете <h:inputText> компонент к бобу, как показано ниже:

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

Это действительно незаконно, когда бин не находится в области запроса. UIComponent экземпляры имеют область действия запроса и могут не использоваться несколькими запросами. Более того, UIComponent экземпляры не сериализуются. Только их состояние, но JSF сама об этом позаботится.

Вы должны удалить fooInput свойство, и вам нужно искать другое решение для проблемы, для которой вы ошибочно полагали, что связывание компонента с bean-объектом области видимости будет правильным решением.

  • Если вы намереваетесь получить к нему доступ в другом месте в представлении, например, #{bean.fooInput.value} затем просто свяжите его с областью Facelet без использования свойства bean:

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

    Это будет доступно в другом месте в том же виде через #{fooInput.xxx},

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

  • Если вы намереваетесь установить какой-либо атрибут компонента программно внутри компонента, например fooInput.setStyleClass("someClass"), или же 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");
        // ...
    }
    

    Но лучше задать вопрос или найти ответ, как по-разному решить конкретную проблему, не прибегая к целому компоненту в компоненте поддержки.

Смотрите также:


Что касается ViewExpiredException это имеет разные основания, которые более подробно рассматриваются в javax.faces.application.ViewExpiredException: представление не может быть восстановлено.

Другие вопросы по тегам