ViewScoped Bean 引起了 NotSerializableException。

9

你好,我正在使用一个ViewScoped Bean。问题是当我调用它时,我会得到NotSerializableException。

这是我的Managed Bean的代码:

@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

有没有解决这个问题的方法?请帮忙!

1
非常相似的问题,有解决方案,请参考这里:https://dev59.com/v3A75IYBdhLWcg3wqKx0 - skaffman
3个回答

7
另一个问题是,MyFaces默认情况下会对状态进行序列化,即使状态正在服务器上保存(默认情况下)。这反过来要求视图作用域后备bean必须是可序列化的。
这种方法的优点是历史记录是真正的历史记录。当您返回到以前的视图版本(使用后退按钮)时,您实际上获得了该时间点后备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。


0

ViewScoped bean 中的所有内容都存储在 ViewState 中。您可以在会话中关闭 ViewState 序列化,但会话本身可以被序列化,然后问题将在其他地方出现。

使用 Spring 的解决方案是使用 Serializable Proxy

<aop:scoped-proxy proxy-target-class="true"/>

Spring beans被包装在代理中,该代理是可序列化的,而被包装的引用是瞬态的,因此在反序列化后从spring上下文重新读取。

从技术上讲,这与elias的答案类似,只是您不需要为每个bean自己编写该代码。您可以利用aop

您可以查看我的问题:JSF beans and serializability issue以获取更多上下文。


0

我在关于同样问题的我的问题上发布了一个解决方案,方法如下:不要通过@ManagedProperty注释(在ManagedBean初始化时执行)使用EL注入Spring bean,而是在运行时评估EL以获取bean。

采用这种方法,您的JSF bean应该如下所示:

@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);
    }
}

这样做可以消除Spring bean属性(代价是进行更多的EL评估),从而避免了在第一次出现属性时出现的序列化问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接