I've read @EJB in @ViewScoped managed bean causes java.io.NotSerializableException, but my state saving setting is server
.
Here is what I have:
web.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>sispra</display-name>
<welcome-file-list>
<welcome-file>index.jsf</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>facelets.BUILD_BEFORE_RESTORE</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.PRETTY_HTML</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>glass-x</param-value>
</context-param>
<security-constraint>
<web-resource-collection>
<web-resource-name>Secure Application</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>fileRealm</realm-name>
</login-config>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
customer.xhtml
:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>TODO supply a title</title>
</h:head>
<h:body>
<p:growl id="messages"/>
<h:form>
<p:commandButton actionListener="#{customerController.create}" value="save" update="@form :messages"/>
<p:panel>
<f:facet name="header">
<h:outputText value="Details"/>
</f:facet>
<h:panelGrid columns="3">
<h:outputLabel for="name" value="#{bundle['person.name']}"/>
<p:inputText id="name" label="#{bundle['person.name']}" value="#{customerController.selected.name}"/>
<p:message for="name"/>
<h:outputLabel for="surname" value="#{bundle['person.surname']}"/>
<p:inputText id="surname" label="#{bundle['person.surname']}" value="#{customerController.selected.surname}"/>
<p:message for="surname"/>
</h:panelGrid>
</p:panel>
</h:form>
</h:body>
</html>
CustomerController.java
:
package it.shape.sispra.controllers;
import it.shape.sispra.ejb.PersonFacade;
import it.shape.sispra.entities.Customer;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class CustomerController extends AbstractController<Customer>
{
private static final long serialVersionUID = 134755304347034L;
@EJB
private PersonFacade facade;
public CustomerController()
{
super(Customer.class);
}
@Override
public PersonFacade getFacade()
{
return facade;
}
}
PersonFacade.java
:
package it.shape.sispra.ejb;
import it.shape.sispra.entities.Person;
import javax.ejb.Stateless;
@Stateless
public class PersonFacade extends AbstractFacade<Person>
{
private static final long serialVersionUID = 4357823648345L;
public PersonFacade()
{
super(Person.class);
}
}
AbstractFacade.java:
package it.shape.sispra.ejb;
import it.shape.sispra.entities.AbstractEntity;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.eclipse.persistence.jpa.JpaHelper;
import org.eclipse.persistence.queries.QueryByExamplePolicy;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReadObjectQuery;
public abstract class AbstractFacade<T extends AbstractEntity> implements Serializable
{
private static final long serialVersionUID = 12467890452346123L;
@PersistenceContext(unitName = "sispra")
private EntityManager em;
private final Class<T> entityClass;
public AbstractFacade(Class<T> entityClass)
{
this.entityClass = entityClass;
}
public EntityManager getEntityManager()
{
return em;
}
public void create(T entity)
{
getEntityManager().persist(entity);
}
public void edit(T entity)
{
getEntityManager().merge(entity);
}
public void remove(T entity)
{
getEntityManager().remove(getEntityManager().merge(entity));
}
public void refresh(T entity)
{
getEntityManager().refresh(entity);
}
public T find(Object id)
{
return getEntityManager().find(entityClass, id);
}
public List<T> findAll()
{
CriteriaQuery<T> cq = getEntityManager().getCriteriaBuilder().createQuery(entityClass);
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int first, int max)
{
CriteriaQuery<T> cq = getEntityManager().getCriteriaBuilder().createQuery(entityClass);
cq.select(cq.from(entityClass));
TypedQuery<T> q = getEntityManager().createQuery(cq);
q.setMaxResults(max);
q.setFirstResult(first);
return q.getResultList();
}
public int count()
{
CriteriaQuery<Long> cq = getEntityManager().getCriteriaBuilder().createQuery(Long.class);
Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
TypedQuery<Long> q = getEntityManager().createQuery(cq);
return q.getSingleResult().intValue();
}
@SuppressWarnings("unchecked")
public T findByExample(T entity)
{
// Create a native EclipseLink query using QBE policy
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "like");
ReadObjectQuery roq = new ReadObjectQuery(entity, policy);
// Wrap the native query in a standard JPA Query and execute it
Query query = JpaHelper.createQuery(roq, getEntityManager());
return (T) query.getSingleResult();
}
@SuppressWarnings("unchecked")
public List<T> findAllByExample(T entity)
{
// Create a native EclipseLink query using QBE policy
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "like");
ReadAllQuery raq = new ReadAllQuery(entity, policy);
// Wrap the native query in a standard JPA Query and execute it
Query query = JpaHelper.createQuery(raq, getEntityManager());
return query.getResultList();
}
@SuppressWarnings("unchecked")
public List<T> findByExample(T entity, int start, int max)
{
// Create a native EclipseLink query using QBE policy
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "like");
ReadAllQuery raq = new ReadAllQuery(entity, policy);
// Wrap the native query in a standard JPA Query and execute it
Query query = JpaHelper.createQuery(raq, getEntityManager());
query.setFirstResult(start);
query.setMaxResults(max);
return query.getResultList();
}
public int countByExample(T entity)
{
//TODO find a better way...
return findAllByExample(entity).size();
}
}
and this is the stacktrace:
GRAVE: Exiting serializeView - Could not serialize state: com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate
java.io.NotSerializableException: com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at java.util.HashMap.writeObject(HashMap.java:1001)
at sun.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1346)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1154)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at java.util.HashMap.writeObject(HashMap.java:1001)
at sun.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1346)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1154)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at org.apache.myfaces.renderkit.ServerSideStateCacheImpl.serializeView(ServerSideStateCacheImpl.java:357)
at org.apache.myfaces.renderkit.ServerSideStateCacheImpl.saveSerializedViewInServletSession(ServerSideStateCacheImpl.java:220)
at org.apache.myfaces.renderkit.ServerSideStateCacheImpl.saveSerializedView(ServerSideStateCacheImpl.java:798)
at org.apache.myfaces.renderkit.html.HtmlResponseStateManager.saveState(HtmlResponseStateManager.java:127)
at org.apache.myfaces.application.StateManagerImpl.saveView(StateManagerImpl.java:166)
at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1554)
at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:281)
at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:85)
at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:239)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:191)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
I know I can workaround this by declaring PersonFacade
as transient
and use JNDI to get EJB reference after recontruction, but I really dislike this approach.
Is it possible that Glassfish 3.1.1 provides non-serializable EJBs? Is there a way to use @EJB
and @ViewScoped
together?
update: i found that this is a MyFaces related issue, all is working fine using mojarra
I have seen the problem too. What I have done in the past is split my bean into a StateBean
which is @ViewScoped
and an ActionsBean
which is @RequestScoped
. The ActionBean
is injected with the StateBean
as well as any EJBs or non-serializable resource accessing objects. On the front-end you use the StateBean
for accessing properties and ActionsBean
for performing actions.
I would love to hear from someone else who would make my "bean splitting" pattern deprecated.
This is an example of what I do:
@ManagedBean
@ViewScoped
public class CustomControllerStateBean implements Serializable {
private static final long serialVersionUID = 134755304347034L;
private Person selected;
public Person getSelected() {
return selected;
}
public void setSelected(Person selected) {
this.selected = selected;
}
}
Notice CustomControllerStateBean
is @ViewScoped
and is Serializable
an only contains Serializable
objects.
@ManagedBean
@RequestScoped
public class CustomControllerActionsBean {
@EJB
private PersonFacade facade;
@Inject
private CustomControllerStateBean state;
public void create() {
facade.create(state.getSelected());
}
}
Notice CustomControllerActionsBean
is @RequestScoped
and is NOT Serializable
an contains non-Serializable
objects.
Your front-end will no look like this:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>TODO supply a title</title>
</h:head>
<h:body>
<p:growl id="messages"/>
<h:form>
<p:commandButton actionListener="#{customerControllerActionsBean.create}" value="save" update="@form :messages"/>
<p:panel>
<f:facet name="header">
<h:outputText value="Details"/>
</f:facet>
<h:panelGrid columns="3">
<h:outputLabel for="name" value="#{bundle['person.name']}"/>
<p:inputText id="name" label="#{bundle['person.name']}" value="#{customerControllerStateBean.selected.name}"/>
<p:message for="name"/>
<h:outputLabel for="surname" value="#{bundle['person.surname']}"/>
<p:inputText id="surname" label="#{bundle['person.surname']}" value="#{customerControllerStateBean.selected.surname}"/>
<p:message for="surname"/>
</h:panelGrid>
</p:panel>
</h:form>
</h:body>
</html>
Notice CustomControllerActionsBean
is used at the top in the p:commandButton
and CustomControllerStateBean
is used in the p:inputText
s.
:) I had the same problem: https://issues.apache.org/jira/browse/MYFACES-3581
David Blevins over at the Apache TomEE helped me a log a bug and patch for MyFaces. The problem was generated proxy classes aren't on the classloader path for their deserializer.
A workaround is to set this web-app param to false: org.apache.myfaces.SERIALIZE_STATE_IN_SESSION
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With