Бин ViewScoped вызывает NotSerializableException
Здравствуйте, я использую компонент ViewScoped. Проблема в том, что при вызове я получаю исключение NotSerializableException.
Это код моего управляемого компонента:
@ManagedBean(name="demandesBean")
@ViewScoped
public class DemandesBean implements Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value="#{demandeService}")
private DemandeService demandeService; //A Spring Service
@ManagedProperty(value="#{loginBean}")
private LoginBean loginBean;
private DemandeVO newDemande;
@PostConstruct
public void initData() {
newDemande = new DemandeVO();
}
public void doAjouterDemande(ActionListener event) {
demandeService.createDemande(newDemande, loginBean.getUsername());
newDemande = new DemandeVO();
}
public List<DemandeVO> getListDemande() {
return demandeService.getAllDemandesByUser(loginBean.getUsername());
}
public DemandeService getDemandeService() {
return demandeService;
}
public void setDemandeService(DemandeService demandeService) {
this.demandeService = demandeService;
}
public LoginBean getLoginBean() {
return loginBean;
}
public void setLoginBean(LoginBean loginBean) {
this.loginBean = loginBean;
}
public DemandeVO getNewDemande() {
return newDemande;
}
public void setNewDemande(DemandeVO newDemande) {
this.newDemande = newDemande;
}
}
Я получаю следующее исключение:
GRAVE: Exiting serializeView - Could not serialize state: com.bull.congesJBPM.serviceImpl.DemandeServiceImpl
java.io.NotSerializableException: com.bull.congesJBPM.serviceImpl.DemandeServiceImpl
Любое решение этой проблемы? Пожалуйста помоги!
3 ответа
Другая проблема заключается в том, что MyFaces по умолчанию выполняет сериализацию состояния, даже когда состояние сохраняется на сервере (по умолчанию). Это, в свою очередь, требует, чтобы поддерживающие bean-компоненты видимости были сериализуемыми.
Плюсы этого подхода в том, что история - это действительно история. Когда вы возвращаетесь к предыдущей версии представления (используя кнопку "назад"), вы фактически получаете точную версию компонента поддержки в то время.
Суть в том, что кажется, что это мешает внедрению сервисов (и не имеет отношения к этой проблеме, является основным ударом по производительности). Точно такие же проблемы возникают при внедрении службы EJB.
Есть параметр контекста, который вы можете поместить в web.xml, чтобы отключить это поведение:
<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>false</param-value>
</context-param>
Смотрите http://wiki.apache.org/myfaces/Performance
Кстати, Mojarra имеет аналогичную настройку, но там по умолчанию установлено значение false.
Я опубликовал решение этой проблемы на свой вопрос об этой же проблеме, который выглядит следующим образом: вместо внедрения бобов Spring через EL в @ManagedProperty
Аннотация (выполняется при инициализации ManagedBean), вы получаете bean-компоненты, оценивающие EL во время выполнения.
При таком подходе ваш компонент JSF должен выглядеть следующим образом:
@ManagedBean(name="demandesBean")
@ViewScoped
public class DemandesBean implements Serializable {
private static final long serialVersionUID = 1L;
private static DemandeService demandeService() {
return SpringJSFUtil.getBean("demandeService");
}
// ...
public void doAjouterDemande(ActionListener event) {
demandeService().createDemande(newDemande, loginBean.getUsername());
newDemande = new DemandeVO();
}
// ...
А вот это используемая служебная программа класса SpringJSFUtil.java:
import javax.faces.context.FacesContext;
public class SpringJSFUtil {
public static <T> T getBean(String beanName) {
if (beanName == null) {
return null;
}
return getValue("#{" + beanName + "}");
}
@SuppressWarnings("unchecked")
private static <T> T getValue(String expression) {
FacesContext context = FacesContext.getCurrentInstance();
return (T) context.getApplication().evaluateExpressionGet(context,
expression, Object.class);
}
}
Это устраняет свойство bean-компонента Spring (за счет выполнения нескольких дополнительных оценок EL), что позволяет избежать проблем сериализации, связанных с наличием свойства на первом месте.
Все в компоненте ViewScoped хранится в ViewState. Вы можете отключить сериализацию ViewState в сеансе, но сами сеансы можно сериализовать, и тогда проблема возникнет в другом месте.
Решение с использованием Spring заключается в использовании Serializable Proxy.
<aop:scoped-proxy proxy-target-class="true"/>
Spring bean-объекты обернуты в прокси, который сериализуем, а обернутая ссылка является временной, поэтому после десериализации она перечитывается из контекста Spring.
Технически это похоже на ответ elias, только вам не нужно самостоятельно писать этот код для каждого компонента. Вы используете AOP.
Вы можете увидеть мой вопрос: JSF-бины и проблема сериализуемости для большего контекста.