9
votes

Hello I'm using a ViewScoped Bean the Problem is that when call it I get the NotSerializableException.

This is the code of my 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;
    }
}

I Recieve The following Exception :

GRAVE: Exiting serializeView - Could not serialize state: com.bull.congesJBPM.serviceImpl.DemandeServiceImpl
java.io.NotSerializableException: com.bull.congesJBPM.serviceImpl.DemandeServiceImpl

Any fix for this problem ?? Please Help !

3
Very similar question, with resolution, here: stackoverflow.com/questions/3180963/…skaffman

3 Answers

7
votes

Another problem is that MyFaces by default does serialization of state, even when state is being saved on the server (the default). This on its turn requires view scoped backing beans to be serializable.

The pros of this approach is that history is truly history. When you go back to a previous view version (using the back-button), you actually get the exact version of the backing bean at that time.

The con is that it seems to break injection of services (and unrelated to this problem, is a major performance hit). The exact same problems happens when injecting an EJB service.

There's a context parameter that you can put in web.xml to disable this behavior:

<context-param>
    <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
    <param-value>false</param-value>
</context-param>

See http://wiki.apache.org/myfaces/Performance

Incidentally, Mojarra has a similar setting but there the default is false.

0
votes

I posted a solution for this problem on my own question about this same problem, that goes like this: instead of injecting the Spring beans via EL in a @ManagedProperty annotation (executed on the ManagedBean initialization), you obtain the beans evaluating the EL at runtime.

With this approach, your JSF bean should look like this:

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

And here it is the used utility class 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);
    }
}

This eliminates the Spring bean property (at the cost of doing a few more EL evaluations), thus avoiding the serialization issues of having the property in first place.

0
votes

Everything in ViewScoped bean is stored in ViewState. You can switch off ViewState serialization in session, but sessions themselves can be serialized and then the problem will arize in other place.

The solution with Spring is to used Serializable Proxy.

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

Spring beans are wrapped in proxy, that is serializable, and the wrapped reference is transient, so it is re-read from spring context after deserialization.

It is technically similar to elias answer, only you don't need to write that code yourself for each bean. You utilize aop.

You can see my question: JSF beans and serializability issue for more context.